Repository: chipsalliance/Cores-SweRV-EL2 Branch: main Commit: 5b10fd96a60d Files: 603 Total size: 5.2 MB Directory structure: gitextract_0gg5endz/ ├── .github/ │ ├── scripts/ │ │ ├── breakpoint.sh │ │ ├── common.inc.sh │ │ ├── convert_dat.sh │ │ ├── create_merged_package.sh │ │ ├── gdb_test.sh │ │ ├── gdb_test_golden.txt │ │ ├── get_code_hash.sh │ │ ├── indexgen/ │ │ │ ├── .gitignore │ │ │ ├── Makefile │ │ │ ├── dashboard-styles/ │ │ │ │ ├── gcov.css │ │ │ │ └── main.css │ │ │ ├── generate.py │ │ │ ├── index_redirect/ │ │ │ │ └── index.html │ │ │ ├── requirements.txt │ │ │ ├── source.template/ │ │ │ │ ├── conf.py │ │ │ │ ├── coverage_dashboard.md │ │ │ │ ├── dev.md │ │ │ │ ├── index.md │ │ │ │ ├── main.md │ │ │ │ └── verification_dashboard.md │ │ │ └── update_styles.sh │ │ ├── info_process_setup.sh │ │ ├── mapfile │ │ ├── openocd/ │ │ │ ├── board/ │ │ │ │ ├── caliptra-verilator-rst.cfg │ │ │ │ └── caliptra-verilator.cfg │ │ │ ├── sim-jtagdpi.cfg │ │ │ ├── veer-el2-rst.cfg │ │ │ └── veer-el2.cfg │ │ ├── openocd_test.sh │ │ ├── peripheral_access.tcl │ │ ├── prepare_coverage_data.sh │ │ ├── pytest/ │ │ │ ├── bar.html │ │ │ ├── css/ │ │ │ │ └── styles.css │ │ │ ├── script/ │ │ │ │ └── script.js │ │ │ └── style_pytest_report.sh │ │ ├── requirements-coverage.txt │ │ ├── riscv_dv_matrix_include.py │ │ ├── riscv_dv_parse_testlist.py │ │ ├── run_regression_test.sh │ │ ├── run_regression_tests.sh │ │ ├── secrets_version │ │ ├── test.gdb │ │ └── utils.sh │ └── workflows/ │ ├── build-docs.yml │ ├── ci.yml │ ├── custom-lint.yml │ ├── gh-pages-pr-closed.yml │ ├── gh-pages-pr-comment.yml │ ├── gh-pages-pr-remove.yml │ ├── publish-webpage.yml │ ├── report-coverage.yml │ ├── test-openocd.yml │ ├── test-regression-cache-waypack.yml │ ├── test-regression-dcls.yml │ ├── test-regression-exceptions.yml │ ├── test-renode.yml │ ├── test-riscof.yml │ ├── test-riscv-dv.yml │ ├── test-uarch.yml │ ├── test-uvm.yml │ ├── test-verification.yml │ ├── verible-format.yml │ └── verible-lint.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── cm.cfg ├── configs/ │ ├── README.md │ ├── veer.config │ └── veer_config_gen.py ├── design/ │ ├── dbg/ │ │ └── el2_dbg.sv │ ├── dec/ │ │ ├── cdecode │ │ ├── csrdecode_m │ │ ├── csrdecode_mu │ │ ├── decode │ │ ├── el2_dec.sv │ │ ├── el2_dec_decode_ctl.sv │ │ ├── el2_dec_gpr_ctl.sv │ │ ├── el2_dec_ib_ctl.sv │ │ ├── el2_dec_pmp_ctl.sv │ │ ├── el2_dec_tlu_ctl.sv │ │ └── el2_dec_trigger.sv │ ├── dmi/ │ │ ├── dmi_jtag_to_core_sync.v │ │ ├── dmi_mux.v │ │ ├── dmi_wrapper.v │ │ └── rvjtag_tap.v │ ├── el2_dma_ctrl.sv │ ├── el2_mem.sv │ ├── el2_pic_ctrl.sv │ ├── el2_pmp.sv │ ├── el2_veer.sv │ ├── el2_veer_lockstep.sv │ ├── el2_veer_wrapper.sv │ ├── exu/ │ │ ├── el2_exu.sv │ │ ├── el2_exu_alu_ctl.sv │ │ ├── el2_exu_div_ctl.sv │ │ └── el2_exu_mul_ctl.sv │ ├── flist │ ├── flist.formal │ ├── flist.lint │ ├── flist.questa │ ├── ifu/ │ │ ├── el2_ifu.sv │ │ ├── el2_ifu_aln_ctl.sv │ │ ├── el2_ifu_bp_ctl.sv │ │ ├── el2_ifu_compress_ctl.sv │ │ ├── el2_ifu_ic_mem.sv │ │ ├── el2_ifu_iccm_mem.sv │ │ ├── el2_ifu_ifc_ctl.sv │ │ ├── el2_ifu_mem_ctl.sv │ │ └── el2_ifu_tb_memread.sv │ ├── include/ │ │ ├── el2_dec_csr_equ_m.svh │ │ ├── el2_dec_csr_equ_mu.svh │ │ └── el2_def.sv │ ├── lib/ │ │ ├── ahb_to_axi4.sv │ │ ├── axi4_to_ahb.sv │ │ ├── beh_lib.sv │ │ ├── el2_lib.sv │ │ ├── el2_mem_if.sv │ │ ├── el2_regfile_if.sv │ │ └── mem_lib.sv │ └── lsu/ │ ├── el2_lsu.sv │ ├── el2_lsu_addrcheck.sv │ ├── el2_lsu_bus_buffer.sv │ ├── el2_lsu_bus_intf.sv │ ├── el2_lsu_clkdomain.sv │ ├── el2_lsu_dccm_ctl.sv │ ├── el2_lsu_dccm_mem.sv │ ├── el2_lsu_ecc.sv │ ├── el2_lsu_lsc_ctl.sv │ ├── el2_lsu_stbuf.sv │ └── el2_lsu_trigger.sv ├── docs/ │ ├── Makefile │ ├── dashboard-styles/ │ │ ├── gcov.css │ │ └── main.css │ ├── requirements.txt │ ├── source/ │ │ ├── adaptations.md │ │ ├── build-args.md │ │ ├── cache.md │ │ ├── clocks.md │ │ ├── complex-ports.md │ │ ├── conf.py │ │ ├── core-control.md │ │ ├── csrs.md │ │ ├── debugging.md │ │ ├── dual-core-lock-step.md │ │ ├── errata.md │ │ ├── error-protection.md │ │ ├── index.md │ │ ├── interrupt-priority.md │ │ ├── interrupts.md │ │ ├── intro.md │ │ ├── memory-map.md │ │ ├── overview.md │ │ ├── performance.md │ │ ├── physical-memory-protection.md │ │ ├── power.md │ │ ├── simulation-debugging.md │ │ ├── tests.md │ │ ├── timers.md │ │ ├── tock.md │ │ ├── user-mode.md │ │ └── verification.md │ └── update_styles.sh ├── release-notes.md ├── requirements.txt ├── testbench/ │ ├── ahb_lite_2to1_mux.sv │ ├── ahb_lsu_dma_bridge.sv │ ├── ahb_sif.sv │ ├── asm/ │ │ ├── bitmanip.s │ │ ├── cmark.c │ │ ├── cmark.mki │ │ ├── cmark_iccm.ld │ │ ├── cmark_iccm.mki │ │ ├── common.s │ │ ├── crt0.s │ │ ├── dbus_nonblocking_load_error.s │ │ ├── dbus_store_error.s │ │ ├── dside_access_across_region_boundary.s │ │ ├── dside_access_region_prediction_error.s │ │ ├── dside_core_local_access_unmapped_address_error.s │ │ ├── dside_pic_access_error.s │ │ ├── dside_size_misaligned_access_to_non_idempotent_address.s │ │ ├── ebreak_ecall.s │ │ ├── hello_world.ld │ │ ├── hello_world.s │ │ ├── hello_world_dccm.ld │ │ ├── hello_world_iccm.ld │ │ ├── hello_world_iccm.s │ │ ├── icache.ld │ │ ├── icache.s │ │ ├── illegal_instruction.s │ │ ├── infinite_loop.ld │ │ ├── infinite_loop.s │ │ ├── internal_timer_ints.s │ │ ├── iside_core_local_unmapped_address_error.s │ │ ├── iside_fetch_precise_bus_error.s │ │ ├── lsu_trigger_hit.s │ │ ├── machine_external_ints.s │ │ ├── machine_external_vec_ints.s │ │ ├── nmi_pin_assertion.s │ │ ├── printf.c │ │ ├── read_after_read.ld │ │ ├── read_after_read.mki │ │ ├── read_after_read.s │ │ └── tb.h │ ├── axi4_mux/ │ │ ├── arbiter.v │ │ ├── axi_crossbar.v │ │ ├── axi_crossbar_addr.v │ │ ├── axi_crossbar_rd.v │ │ ├── axi_crossbar_wr.v │ │ ├── axi_crossbar_wrap_2x1.v │ │ ├── axi_register_rd.v │ │ ├── axi_register_wr.v │ │ └── priority_encoder.v │ ├── axi_lsu_dma_bridge.sv │ ├── dasm.svi │ ├── flist │ ├── hex/ │ │ ├── user_mode0/ │ │ │ ├── bitmanip.hex │ │ │ ├── clk_override.hex │ │ │ ├── cmark.hex │ │ │ ├── cmark_dccm.hex │ │ │ ├── cmark_iccm.hex │ │ │ ├── core_pause.hex │ │ │ ├── csr_access.hex │ │ │ ├── csr_misa.hex │ │ │ ├── csr_mstatus.hex │ │ │ ├── dbus_nonblocking_load_error.hex │ │ │ ├── dbus_store_error.hex │ │ │ ├── dhry.hex │ │ │ ├── dside_access_across_region_boundary.hex │ │ │ ├── dside_access_region_prediction_error.hex │ │ │ ├── dside_core_local_access_unmapped_address_error.hex │ │ │ ├── dside_pic_access_error.hex │ │ │ ├── dside_size_misaligned_access_to_non_idempotent_address.hex │ │ │ ├── ebreak_ecall.hex │ │ │ ├── ecc.hex │ │ │ ├── hello_world.hex │ │ │ ├── hello_world_dccm.hex │ │ │ ├── hello_world_iccm.hex │ │ │ ├── icache.hex │ │ │ ├── illegal_instruction.hex │ │ │ ├── infinite_loop.hex │ │ │ ├── insns.hex │ │ │ ├── internal_timer_ints.hex │ │ │ ├── irq.hex │ │ │ ├── iside_core_local_unmapped_address_error.hex │ │ │ ├── iside_fetch_precise_bus_error.hex │ │ │ ├── lsu_trigger_hit.hex │ │ │ ├── machine_external_ints.hex │ │ │ ├── machine_external_vec_ints.hex │ │ │ ├── modesw.hex │ │ │ ├── nmi_pin_assertion.hex │ │ │ ├── perf_counters.hex │ │ │ ├── pmp.hex │ │ │ ├── pmp_random.hex │ │ │ └── write_unaligned.hex │ │ └── user_mode1/ │ │ ├── bitmanip.hex │ │ ├── clk_override.hex │ │ ├── cmark.hex │ │ ├── cmark_dccm.hex │ │ ├── cmark_iccm.hex │ │ ├── core_pause.hex │ │ ├── csr_access.hex │ │ ├── csr_misa.hex │ │ ├── csr_mseccfg.hex │ │ ├── csr_mstatus.hex │ │ ├── dbus_nonblocking_load_error.hex │ │ ├── dbus_store_error.hex │ │ ├── dhry.hex │ │ ├── dside_access_across_region_boundary.hex │ │ ├── dside_access_region_prediction_error.hex │ │ ├── dside_core_local_access_unmapped_address_error.hex │ │ ├── dside_pic_access_error.hex │ │ ├── dside_size_misaligned_access_to_non_idempotent_address.hex │ │ ├── ebreak_ecall.hex │ │ ├── ecc.hex │ │ ├── hello_world.hex │ │ ├── hello_world_dccm.hex │ │ ├── hello_world_iccm.hex │ │ ├── icache.hex │ │ ├── illegal_instruction.hex │ │ ├── infinite_loop.hex │ │ ├── insns.hex │ │ ├── internal_timer_ints.hex │ │ ├── irq.hex │ │ ├── iside_core_local_unmapped_address_error.hex │ │ ├── iside_fetch_precise_bus_error.hex │ │ ├── lsu_trigger_hit.hex │ │ ├── machine_external_ints.hex │ │ ├── machine_external_vec_ints.hex │ │ ├── modesw.hex │ │ ├── nmi_pin_assertion.hex │ │ ├── perf_counters.hex │ │ ├── pmp.hex │ │ ├── pmp_random.hex │ │ └── write_unaligned.hex │ ├── icache_macros.svh │ ├── input.tcl │ ├── jtagdpi/ │ │ ├── README.md │ │ ├── jtagdpi.c │ │ ├── jtagdpi.h │ │ └── jtagdpi.sv │ ├── link.ld │ ├── openocd_scripts/ │ │ ├── common.tcl │ │ ├── jtag_cg.tcl │ │ ├── sim-jtagdpi.cfg │ │ ├── veer-el2-rst.cfg │ │ └── verilator-rst.cfg │ ├── tb_top.sv │ ├── tb_top_pkg.sv │ ├── tcp_server/ │ │ ├── tcp_server.c │ │ └── tcp_server.h │ ├── test_tb_top.cpp │ ├── tests/ │ │ ├── clk_override/ │ │ │ ├── clk_override.c │ │ │ ├── clk_override.ld │ │ │ ├── clk_override.mki │ │ │ └── crt0.s │ │ ├── core_pause/ │ │ │ ├── core_pause.c │ │ │ ├── core_pause.ld │ │ │ ├── core_pause.mki │ │ │ └── crt0.s │ │ ├── csr_access/ │ │ │ ├── crt0.s │ │ │ ├── csr_access.c │ │ │ ├── csr_access.ld │ │ │ ├── csr_access.mki │ │ │ └── veer.c │ │ ├── csr_misa/ │ │ │ ├── crt0.s │ │ │ ├── csr_misa.c │ │ │ ├── csr_misa.ld │ │ │ └── csr_misa.mki │ │ ├── csr_mseccfg/ │ │ │ ├── crt0.s │ │ │ ├── csr_mseccfg.c │ │ │ ├── csr_mseccfg.ld │ │ │ └── csr_mseccfg.mki │ │ ├── csr_mstatus/ │ │ │ ├── crt0.s │ │ │ ├── csr_mstatus.c │ │ │ ├── csr_mstatus.ld │ │ │ └── csr_mstatus.mki │ │ ├── dhry/ │ │ │ ├── dhry.h │ │ │ ├── dhry.mki │ │ │ ├── dhry_1.c │ │ │ └── dhry_2.c │ │ ├── ecc/ │ │ │ ├── crt0.s │ │ │ ├── ecc.c │ │ │ ├── ecc.ld │ │ │ └── ecc.mki │ │ ├── insns/ │ │ │ ├── crt0.s │ │ │ ├── insns.c │ │ │ ├── insns.ld │ │ │ └── insns.mki │ │ ├── irq/ │ │ │ ├── crt0.s │ │ │ ├── irq.c │ │ │ ├── irq.ld │ │ │ └── irq.mki │ │ ├── modesw/ │ │ │ ├── README.md │ │ │ ├── crt0.s │ │ │ ├── modesw.c │ │ │ ├── modesw.ld │ │ │ └── modesw.mki │ │ ├── perf_counters/ │ │ │ ├── crt0.s │ │ │ ├── perf_counters.c │ │ │ ├── perf_counters.ld │ │ │ ├── perf_counters.mki │ │ │ └── veer.c │ │ ├── pmp/ │ │ │ ├── crt0.s │ │ │ ├── fault.c │ │ │ ├── fault.h │ │ │ ├── main.c │ │ │ ├── pmp.c │ │ │ ├── pmp.h │ │ │ ├── pmp.ld │ │ │ ├── pmp.mki │ │ │ ├── trap.h │ │ │ ├── veer.c │ │ │ └── veer.h │ │ ├── pmp_random/ │ │ │ ├── generate_random.sh │ │ │ ├── main.c │ │ │ ├── pmp_random.mki │ │ │ └── random_data.h │ │ └── write_unaligned/ │ │ ├── crt0.s │ │ ├── write_unaligned.c │ │ ├── write_unaligned.ld │ │ └── write_unaligned.mki │ ├── user_cells.sv │ └── veer_wrapper.sv ├── tools/ │ ├── JSON.pm │ ├── Makefile │ ├── addassign │ ├── coredecode │ ├── hex_canned_update.sh │ ├── picmap │ ├── picolibc.mk │ ├── prefix_macros.sh │ ├── renode/ │ │ ├── README.md │ │ ├── build-all-tests.sh │ │ ├── veer.repl │ │ ├── veer.resc │ │ ├── veer.robot │ │ └── veer_smepmp.repl │ ├── riscof/ │ │ ├── README.md │ │ ├── config.ini │ │ ├── spike/ │ │ │ ├── env/ │ │ │ │ ├── link.ld │ │ │ │ └── model_test.h │ │ │ ├── riscof_spike.py │ │ │ ├── spike_isa.yaml │ │ │ └── spike_platform.yaml │ │ └── veer/ │ │ ├── env/ │ │ │ ├── link.ld │ │ │ └── model_test.h │ │ ├── riscof_veer.py │ │ ├── veer_isa.yaml │ │ └── veer_platform.yaml │ ├── riscv-dv/ │ │ ├── Makefile │ │ ├── README.md │ │ ├── code_fixup.py │ │ ├── riscv_core_setting.py │ │ ├── riscv_core_setting.sv │ │ ├── testlist.yaml │ │ ├── user_extension.svh │ │ ├── veer_directed_instr_lib.sv │ │ └── veer_log_to_trace_csv.py │ ├── smalldiv │ ├── unrollforverilator │ └── vivado.tcl ├── verification/ │ ├── block/ │ │ ├── .flake8 │ │ ├── __init__.py │ │ ├── common/ │ │ │ ├── axi.py │ │ │ ├── csrs.py │ │ │ └── utils.py │ │ ├── common.mk │ │ ├── config.vlt │ │ ├── dccm/ │ │ │ ├── Makefile │ │ │ ├── config.vlt │ │ │ ├── el2_lsu_dccm_mem_wrapper.sv │ │ │ ├── test_readwrite.py │ │ │ └── testbench.py │ │ ├── dcls/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── el2_veer_lockstep_wrapper.sv │ │ │ ├── test_lockstep.py │ │ │ └── testbench.py │ │ ├── dec/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── el2_dec_wrapper.sv │ │ │ ├── test_dec.py │ │ │ └── testbench.py │ │ ├── dec_ib/ │ │ │ ├── Makefile │ │ │ ├── config.vlt │ │ │ ├── el2_dec_ib_ctl_wrapper.sv │ │ │ ├── test_dec_ib.py │ │ │ └── testbench.py │ │ ├── dec_pmp_ctl/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── test_dec_pmp_ctl.py │ │ │ └── testbench.py │ │ ├── dec_tl/ │ │ │ ├── Makefile │ │ │ ├── config.vlt │ │ │ ├── el2_dec_trigger_wrapper.sv │ │ │ ├── test_dec_tl.py │ │ │ └── testbench.py │ │ ├── dec_tlu_ctl/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── common.py │ │ │ ├── el2_tlu_ctl_wrapper.sv │ │ │ ├── test_dec_tl.py │ │ │ └── testbench.py │ │ ├── dma/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── scoreboards.py │ │ │ ├── sequences.py │ │ │ ├── test_address.py │ │ │ ├── test_debug_address.py │ │ │ ├── test_debug_read.py │ │ │ ├── test_debug_write.py │ │ │ ├── test_ecc.py │ │ │ ├── test_read.py │ │ │ ├── test_reset.py │ │ │ ├── test_write.py │ │ │ └── testbench.py │ │ ├── dmi/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── common.py │ │ │ ├── config.vlt │ │ │ ├── dmi_agent.py │ │ │ ├── dmi_bfm.py │ │ │ ├── dmi_seq.py │ │ │ ├── dmi_test_wrapper.sv │ │ │ ├── jtag_agent.py │ │ │ ├── jtag_bfm.py │ │ │ ├── jtag_pkg.py │ │ │ ├── jtag_predictor.py │ │ │ ├── jtag_seq.py │ │ │ ├── test_dmi_read_write.py │ │ │ ├── test_dmi_tap_fsm.py │ │ │ ├── test_jtag_ir.py │ │ │ └── testbench.py │ │ ├── exu_alu/ │ │ │ ├── Makefile │ │ │ ├── config.vlt │ │ │ ├── el2_exu_alu_ctl_wrapper.sv │ │ │ ├── test_arith.py │ │ │ ├── test_logic.py │ │ │ ├── test_zba.py │ │ │ ├── test_zbb.py │ │ │ ├── test_zbp.py │ │ │ ├── test_zbs.py │ │ │ └── testbench.py │ │ ├── exu_div/ │ │ │ ├── Makefile │ │ │ ├── config.vlt │ │ │ ├── el2_exu_div_ctl_wrapper.sv │ │ │ ├── test_div.py │ │ │ └── testbench.py │ │ ├── exu_mul/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── config.vlt │ │ │ ├── el2_exu_mul_ctl_wrapper.sv │ │ │ ├── test_mul.py │ │ │ └── testbench.py │ │ ├── iccm/ │ │ │ ├── Makefile │ │ │ ├── config.vlt │ │ │ ├── el2_ifu_iccm_mem_wrapper.sv │ │ │ ├── test_readwrite.py │ │ │ └── testbench.py │ │ ├── ifu_compress/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── test_compress.py │ │ │ └── testbench.py │ │ ├── ifu_mem_ctl/ │ │ │ ├── Makefile │ │ │ ├── cm.cfg │ │ │ ├── common.py │ │ │ ├── el2_ifu_mem_ctl_wrapper.sv │ │ │ ├── test_err.py │ │ │ ├── test_err_stop.py │ │ │ └── test_miss.py │ │ ├── lib_ahb_to_axi4/ │ │ │ ├── Makefile │ │ │ ├── ahb_to_axi4_wrapper.sv │ │ │ ├── test_read.py │ │ │ ├── test_write.py │ │ │ ├── testbench.py │ │ │ └── ucli.key │ │ ├── lib_axi4_to_ahb/ │ │ │ ├── Makefile │ │ │ ├── ahb_lite_agent.py │ │ │ ├── ahb_lite_bfm.py │ │ │ ├── ahb_lite_pkg.py │ │ │ ├── ahb_lite_seq.py │ │ │ ├── axi_pkg.py │ │ │ ├── axi_r_agent.py │ │ │ ├── axi_r_bfm.py │ │ │ ├── axi_r_seq.py │ │ │ ├── axi_w_agent.py │ │ │ ├── axi_w_bfm.py │ │ │ ├── axi_w_seq.py │ │ │ ├── cm.cfg │ │ │ ├── common.py │ │ │ ├── coordinator_seq.py │ │ │ ├── test_axi.py │ │ │ ├── test_axi_read_channel.py │ │ │ ├── test_axi_write_channel.py │ │ │ ├── testbench.py │ │ │ └── ucli.key │ │ ├── lsu_tl/ │ │ │ ├── Makefile │ │ │ ├── config.vlt │ │ │ ├── el2_lsu_trigger_wrapper.sv │ │ │ ├── test_lsu_tl.py │ │ │ └── testbench.py │ │ ├── noxfile.py │ │ ├── pic/ │ │ │ ├── Makefile │ │ │ ├── test_clken.py │ │ │ ├── test_config.py │ │ │ ├── test_pending.py │ │ │ ├── test_prioritization.py │ │ │ ├── test_reset.py │ │ │ ├── test_servicing.py │ │ │ └── testbench.py │ │ ├── pic_gw/ │ │ │ ├── Makefile │ │ │ └── test_gateway.py │ │ ├── pmp/ │ │ │ ├── Makefile │ │ │ ├── common.py │ │ │ ├── config.vlt │ │ │ ├── el2_pmp_wrapper.sv │ │ │ ├── test_address_matching.py │ │ │ ├── test_multiple_configs.py │ │ │ ├── test_xwr_access.py │ │ │ └── testbench.py │ │ ├── pmp_random/ │ │ │ ├── Makefile │ │ │ ├── config.vlt │ │ │ ├── el2_pmp_wrapper.sv │ │ │ ├── test_pmp_random.py │ │ │ └── testbench.py │ │ ├── pyproject.toml │ │ └── requirements.txt │ ├── test_debug/ │ │ └── test_debug.py │ └── top/ │ ├── README.md │ ├── requirements.txt │ └── test_pyuvm/ │ ├── Makefile │ ├── __init__.py │ ├── cm.cfg │ ├── conftest.py │ ├── test_irq/ │ │ ├── irq_utils.py │ │ ├── irq_uvm.py │ │ └── test_irq.py │ └── test_pyuvm.py └── violations.waiver ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/scripts/breakpoint.sh ================================================ #!/bin/bash # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # set -ex # Invoke GDB ${GCC_PREFIX}-gdb -n --batch -x breakpoint.gdb >gdb.log # Parse the log cat gdb.log | grep 'Breakpoint 1,' >breakpoint.txt # Compare the dumps diff -E -y breakpoint.txt breakpoint_golden.txt || true ================================================ FILE: .github/scripts/common.inc.sh ================================================ #!/bin/bash set -e -u -o pipefail COLOR_CLEAR="\033[0m" COLOR_RED="\033[0;31m" COLOR_GREEN="\033[1;32m" COLOR_YELLOW="\033[1;33m" COLOR_WHITE="\033[1;37m" check_args_count(){ # Check argument count function is meant to be used to check if # the number of received arguments is equal to the expected. # If they are unequal, the function returns with error # Args: # argc_got - Number of received arguments, e.g.: $# # argc_expected - Number of expected arguments, e.g.: 2 argc_got=$1 argc_expected=$2 if [ ${argc_got} -ne ${argc_expected} ]; then echo -e "${COLOR_WHITE}Expected ${argc_expected} arguments, but received ${argc_got} ${COLOR_RED}FAIL${COLOR_CLEAR}" echo -e "${COLOR_WHITE}Caller:${COLOR_CLEAR}" `caller` exit 1 fi } ================================================ FILE: .github/scripts/convert_dat.sh ================================================ #!/bin/bash DAT_FILE="${1}" INFO_FILE="${2}" verilator_coverage --skip-toggle --write-info "${INFO_FILE}_branch.info" "${DAT_FILE}" verilator_coverage --toggle-only --write-info "${INFO_FILE}_toggle.info" "${DAT_FILE}" ================================================ FILE: .github/scripts/create_merged_package.sh ================================================ #!/bin/bash set -eux set -o pipefail # The script needs to be run with V package prepared in data_v # and Verilator package prepared in data_verilator. # Note that config.json will contain output of this script. # It will be basically data_v/config.json with "datasets" key removed # so that it's regenerated by info-process with minor other modifications. python3 <config.json import json with open('data_v/config.json') as f: config = json.load(f) with open('data_verilator/config.json') as f: verilator_config = json.load(f) db_count_v = config['additional'].pop('db_count') config['additional']['db_count_verilator'] = verilator_config['additional']['db_count'] config['additional']['db_count_v'] = db_count_v config['timestamp'] = '`date +"%Y-%m-%dT%H:%M:%S.%3N%z"`' del config['datasets'] print(json.dumps(config, indent=2)) END _out_dir=data_both # The order of INFO files influences order of datasets that will be # generated based on passed INFO files and added to config.json. info-process pack --output $_out_dir --config config.json \ --coverage-files data_v/*.info data_verilator/*.info \ --description-files data_verilator/*.desc data_v/*.desc \ --extra-files data_v/logo.svg cat $_out_dir/config.json echo "Merged coverage data ready to be packaged in $PWD/$_out_dir" ================================================ FILE: .github/scripts/gdb_test.sh ================================================ #!/bin/bash # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script runs Verilator RTL simulation and OpenOCD in background, invokes # the supplied test command and shuts everything down. SIM_LOG=`realpath sim.log` OPENOCD_LOG=`realpath openocd.log` GDB_LOG=`realpath gdb.log` if [ -z $GCC_PREFIX ]; then GCC_PREFIX=riscv64-unknown-elf fi # Ensure that RISC-V toolchain is installed if ! which ${GCC_PREFIX}-gcc >/dev/null; then GCC_PREFIX=riscv32-unknown-elf fi if ! which ${GCC_PREFIX}-gcc >/dev/null; then echo "RISC-V toolchain not found, please refer to https://github.com/chipsalliance/caliptra-rtl?tab=readme-ov-file#riscv-toolchain-installation for more details." exit 1 fi export GCC_PREFIX set +e # Utils source `dirname ${BASH_SOURCE[0]}`/utils.sh terminate_all () { terminate ${OPENOCD_PID} echo "waiting for the simulation to end: $SIM_PID" wait ${SIM_PID} # terminate ${SIM_PID} } print_logs () { echo -e "${COLOR_WHITE}======== OpenOCD log ========${COLOR_OFF}" cat ${OPENOCD_LOG} || true echo -e "${COLOR_WHITE}======== Simulation log ========${COLOR_OFF}" cat ${SIM_LOG} || true echo -e "${COLOR_WHITE}======== GDB log ========${COLOR_OFF}" cat ${GDB_LOG} || true } echo -e "${COLOR_WHITE}======== Launching interactive simulation ========${COLOR_OFF}" # Start the simulation echo -e "Starting simulation..." if [ -f obj_dir/Vtb_top ]; then SIM_START_STRING="VerilatorTB: Start of sim" obj_dir/Vtb_top >"${SIM_LOG}" 2>&1 & elif [ -f ./simv ]; then SIM_START_STRING=" remote_bitbang_port 5000" ./simv +vcs+lic+wait -cm line+cond+fsm+tgl+branch >"${SIM_LOG}" 2>&1 & else echo "No simulation binary found, exiting" exit 1 fi SIM_PID=$! # Wait wait_for_phrase "${SIM_LOG}" "${SIM_START_STRING}" sleep 1s retcode=$? if [ $retcode -ne 0 ]; then echo -e "${COLOR_RED}Failed to start the simulation: $retcode ${COLOR_OFF}" print_logs terminate_all; exit -1 fi echo -e "Simulation running and ready (pid=${SIM_PID})" # Launch OpenOCD echo -e "Launching OpenOCD..." WORKDIR=$PWD cd ${RV_ROOT}/.github/scripts/openocd openocd -d2 --file board/caliptra-verilator.cfg > ${OPENOCD_LOG} 2>&1 & OPENOCD_PID=$! cd $WORKDIR # Wait wait_for_phrase "${OPENOCD_LOG}" "Listening on port 3333 for gdb connections" if [ $? -ne 0 ]; then echo -e "${COLOR_RED}Failed to start OpenOCD!${COLOR_OFF}" print_logs terminate_all; exit -1 fi echo -e "OpenOCD running and ready (pid=${OPENOCD_PID})" # Wait a bit sleep 1s # Run the test echo -e "${COLOR_WHITE}======== Running GDB script test.gdb ========${COLOR_OFF}" ${GCC_PREFIX}-gdb -n --batch -x ${RV_ROOT}/.github/scripts/test.gdb > "${GDB_LOG}" & GDB_PID=$! # The simulation must end naturally in order to produce coverage data. wait ${SIM_PID} # OpenOCD waits endlessly for the target (Vtb_top) to reconnect. # Kill OpenoCD and GDB in case they're stuck kill -s SIGKILL ${OPENOCD_PID} || true kill -s SIGKILL ${GDB_PID} || true # Display logs print_logs # Parse the log, extract register values. Skip those which change as the # program executes since we don't know at which point we tap in. grep -E '^ra |^sp |^gp |^tp |^t[01256] |^s[0-9]+ |^a[0-9]+ |^\$[0-9]+ |^\$ |^Hardware |^Breakpoint' "${GDB_LOG}" > gdb_test_dump.txt gdb_output_golden=${RV_ROOT}/.github/scripts/gdb_test_golden.txt grep -q "TEST_PASSED" "${SIM_LOG}" tb_passed=$? # Compare the dumps diff -E -y ${gdb_output_golden} gdb_test_dump.txt gdb_output_match=$? if [ "$tb_passed" -ne 0 ]; then echo "Testbench failed. The test did not write 0xff to the mailbox to indicate success." exit 1 fi echo "Testbench passed." if [ "$gdb_output_match" -ne 0 ]; then echo "The output from GDB doesn't match the golden reference. See ${gdb_output_golden}" exit 1 fi echo "The output from GDB matches the golden reference." echo "TEST PASSED" ================================================ FILE: .github/scripts/gdb_test_golden.txt ================================================ ra 0x5f555555 0x5f555555 sp 0x0 0x0 gp 0x4 0x4 tp 0x0 0x0 t0 0x0 0 t1 0x0 0 t2 0x0 0 s1 0x0 0 a0 0x0 0 a1 0x0 0 a2 0x0 0 a3 0x0 0 a4 0x0 0 a5 0x0 0 a6 0x0 0 a7 0x0 0 s2 0x0 0 s3 0x0 0 s4 0x0 0 s5 0x0 0 s6 0x0 0 s7 0x0 0 s8 0x0 0 s9 0x0 0 s10 0x0 0 s11 0x0 0 t5 0x0 0 t6 0x0 0 $1 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $2 = 0x55555555 $3 = 0xaaaaaaaa $4 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $5 = 0x55555555 $6 = 0xaaaaaaaa $7 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $8 = 0x55555555 $9 = 0xaaaaaaaa $10 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $11 = 0x55555555 $12 = 0xaaaaaaaa $13 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $14 = 0x55555555 $15 = 0xaaaaaaaa $16 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $17 = 0x55555555 $18 = 0xaaaaaaaa $19 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $20 = 0x55555555 $21 = 0xaaaaaaaa $22 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $23 = 0x55555555 $24 = 0xaaaaaaaa $25 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $26 = 0x55555555 $27 = 0xaaaaaaaa $28 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $29 = 0x55555555 $30 = 0xaaaaaaaa $31 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $32 = 0x55555555 $33 = 0xaaaaaaaa $34 = {0x1234567, 0x89abcdef, 0x55555555, 0xaaaaaaaa} $35 = 0x55555555 $36 = 0xaaaaaaaa Hardware assisted breakpoint 1 at 0x1c Breakpoint 1, 0x0000001c in ?? () ================================================ FILE: .github/scripts/get_code_hash.sh ================================================ #!/bin/bash # This script is responsible for computing hash for RISCV-DV generated programs # cache. HASHES=() HASHES+=($(git submodule status third_party/riscv-dv | cut -d\ -f2)) HASHES+=($(sha256sum tools/riscv-dv/code_fixup.py | cut -d\ -f1)) HASHES+=($(sha256sum tools/riscv-dv/testlist.yaml | cut -d\ -f1)) HASHES+=($(sha256sum tools/riscv-dv/riscv_core_setting.sv | cut -d\ -f1)) HASHES+=($(sha256sum tools/riscv-dv/Makefile | cut -d\ -f1)) HASHES+=($(sha256sum tools/riscv-dv/user_extension.svh | cut -d\ -f1)) HASHES+=($(sha256sum tools/riscv-dv/veer_directed_instr_lib.sv | cut -d\ -f1)) echo ${HASHES[@]} | sha256sum | cut -d\ -f1 ================================================ FILE: .github/scripts/indexgen/.gitignore ================================================ build source ================================================ FILE: .github/scripts/indexgen/Makefile ================================================ SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = source.template GENDIR = source BUILDDIR ?= build ROOTDIR ?= work all: clean html # Sources SOURCES = $(wildcard $(SOURCEDIR)/*.md) # Generate sources $(GENDIR): @mkdir -p $@ $(GENDIR)/index.md: $(SOURCES) generate.py | $(GENDIR) @rm -rf $(GENDIR)/* @python3 generate.py --template "$(SOURCEDIR)" --root "$(ROOTDIR)/html" --output "$(GENDIR)" # Build the final webpage. Pass the 'html' target to sphinx, copy report pages html: Makefile $(GENDIR)/index.md @$(SPHINXBUILD) -M $@ "$(GENDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) @rsync -avrm --include="*/" --include="coverage_dashboard/***" --include="verification_dashboard/***" --include="docs_rendered/***" --exclude="*" "$(ROOTDIR)/" "$(BUILDDIR)/" @bash update_styles.sh "$(BUILDDIR)" clean: @rm -rf $(BUILDDIR) @rm -rf $(GENDIR) .PHONY: all clean html ================================================ FILE: .github/scripts/indexgen/dashboard-styles/gcov.css ================================================ /* All views: initial background and text color */ @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); body { color: #E9EBFA; background-color: #0E1116; padding: 0; margin: 0; font-family: 'Roboto', sans-serif; box-sizing: border-box; } /* * { } */ /* All views: standard link format*/ a:link { color: #00D0C9; text-decoration: underline; font-family: 'Roboto', sans-serif; } /* All views: standard link - visited format */ a:visited { color: #E9EBFA; text-decoration: underline; } /* All views: standard link - activated format */ a:active { color: #00D0C9; color: #E9EBFA; text-decoration: underline; } th { border: 1px solid; } td { color: #E9EBFA; } body > table:nth-child(1) > tbody > tr:nth-child(3) { height: 300px; } body > center > table td:not(.coverBarOutline){ border: 1px solid #31363C; } body > center > table > tbody > tr:nth-child(1) { display: none; } body>table:nth-child(1)>tbody>tr:nth-child(3) { display: flex; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td { align-self: center; padding: 0 95px; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(1) > td.headerValue { font-size: 35px; } body>table:nth-child(1)>tbody>tr:nth-child(3)>td>table>tbody>tr:nth-child(1)>td.headerItem { font-weight: 300; font-size: 35px; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(1) > td.headerValue { font-size: 35px; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(2) > td.headerItem { font-size: 22px; font-weight: 300; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(2) > td.headerValue { font-size: 22px; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(3) > td.headerItem { font-size: 22px; font-weight: 300; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(3) > td.headerValue { font-size: 22px; } body > table:nth-child(1) > tbody > tr:nth-child(1) { position: relative; } body > table:nth-child(1) > tbody > tr:nth-child(1) > td::before { content: url(../../../_static/white.svg); position: absolute; left: 95px; transform: translateY(-15%); } table { border-collapse: collapse; width: 100%; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody { padding: 0 50px; } body > center > table > tbody tr { width: 19px; } /* All views: main title format */ td.title { background-color: #25292E; color: #DFE1F1; text-align: center; padding-bottom: 10px; font-size: 20px; font-weight: bold; padding: 20px 0; } /* All views: header item format */ td.headerItem { text-align: right; padding-right: 6px; font-weight: bold; white-space: nowrap; } /* All views: header item value format */ td.headerValue { text-align: left; color: #00D0C9; font-weight: bold; white-space: nowrap; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(1) > td:nth-child(5)::after { content: ' '; width: 10px; } /* All views: header item coverage table heading */ td.headerCovTableHead { color: #DFE1F1; text-align: center; padding-right: 6px; padding-left: 6px; padding-bottom: 0px; font-size: 14px; white-space: nowrap; } /* All views: header item coverage table entry */ td.headerCovTableEntry { text-align: right; color: #DFE1F1; text-align: center; background-color: #31363C; font-weight: bold; white-space: nowrap; padding-left: 12px; padding-right: 4px; } /* All views: header item coverage table entry for high coverage rate */ td.headerCovTableEntryHi { text-align: right; color: #000000; font-weight: bold; white-space: nowrap; padding-left: 12px; padding-right: 4px; background-color: #2FC36E; } /* All views: header item coverage table entry for medium coverage rate */ td.headerCovTableEntryMed { text-align: right; color: #000000; font-weight: bold; white-space: nowrap; padding-left: 12px; padding-right: 4px; background-color: #EFAC0A; } /* All views: header item coverage table entry for ow coverage rate */ td.headerCovTableEntryLo { text-align: right; color: #DFE1F1; text-align: center; font-weight: bold; white-space: nowrap; padding-left: 12px; padding-right: 4px; background-color: #F21E08; } /* All views: header legend value for legend entry */ td.headerValueLeg { text-align: left; color: #000000; font-size: 80%; white-space: nowrap; padding-top: 4px; } body>table:nth-child(1)>tbody>tr:nth-child(2)>td { display: none; } /* All views: color of horizontal ruler */ td.ruler > img { height: 1px ; width: 100% ; background-color: rgba(255, 255, 255, 0.3); aspect-ratio: 1 / 1; } /* All views: version string format */ td.versionInfo { text-align: center; padding-top: 35px; font-style: italic; } td.versionInfo > a { color: #00D0C9; } /* Directory view/File view (all)/Test case descriptions: table headline format */ td.tableHead { text-align: center; color: #ffffff; background-color: #0E1116; font-size: 16px; font-weight: bold; white-space: nowrap; padding-left: 4px; padding-right: 4px; } span.tableHeadSort { padding-right: 4px; } td { align-items: center; } center { padding: 95px; } /* Directory view/File view (all): filename entry format */ td.coverFile { text-align: left; padding-left: 10px; padding-right: 20px; color: #E9EBFA; background-color: #0E1116; font-family: monospace; } /* Directory view/File view (all): bar-graph entry format*/ td.coverBar { background-color: #0E1116; } /* Directory view/File view (all): bar-graph outline color */ td.coverBarOutline { background-color: #0E1116; display: flex; justify-content: center; } /* Directory view/File view (all): percentage entry for files with high coverage rate */ td.coverPerHi { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #0E1116; color: #2FC36E; font-weight: bold; } /* Directory view/File view (all): line count entry for files with high coverage rate */ td.coverNumHi { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #0E1116; white-space: nowrap; } /* Directory view/File view (all): percentage entry for files with medium coverage rate */ td.coverPerMed { text-align: right; padding-left: 10px; padding-right: 10px; color: #EFAC0A; background-color: #0E1116; font-weight: bold; } /* Directory view/File view (all): line count entry for files with medium coverage rate */ td.coverNumMed { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #0E1116; white-space: nowrap; } /* Directory view/File view (all): percentage entry for files with low coverage rate */ td.coverPerLo { text-align: right; padding-left: 10px; padding-right: 10px; color: #F21E08; background-color: #0E1116; font-weight: bold; } /* Directory view/File view (all): line count entry for files with low coverage rate */ td.coverNumLo { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #0E1116; white-space: nowrap; } /* File view (all): "show/hide details" link format */ a.detail:link { color: #B8D0FF; font-size:80%; } /* File view (all): "show/hide details" link - visited format */ a.detail:visited { color: #B8D0FF; font-size:80%; } /* File view (all): "show/hide details" link - activated format */ a.detail:active { color: #ffffff; font-size:80%; } /* File view (detail): test name entry */ td.testName { text-align: right; padding-right: 10px; background-color: #dae7fe; } /* File view (detail): test percentage entry */ td.testPer { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #dae7fe; } /* File view (detail): test lines count entry */ td.testNum { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #dae7fe; } /* Test case descriptions: test name format*/ dt { font-weight: bold; } /* Test case descriptions: description table body */ td.testDescription { padding-top: 10px; padding-left: 30px; padding-bottom: 10px; padding-right: 30px; background-color: #dae7fe; } /* Source code view: function entry */ td.coverFn { text-align: left; padding-left: 10px; padding-right: 20px; color: #284fa8; background-color: #dae7fe; font-family: monospace; } /* Source code view: function entry zero count*/ td.coverFnLo { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #ff0000; font-weight: bold; } /* Source code view: function entry nonzero count*/ td.coverFnHi { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #dae7fe; font-weight: bold; } /* Source code view: source code format */ pre.source { font-family: monospace; white-space: pre; margin-top: 2px; } /* Source code view: line number format */ span.lineNum { background-color: #efe383; } /* Source code view: format for lines which were executed */ td.lineCov, span.lineCov { background-color: #cad7fe; } /* Source code view: format for Cov legend */ span.coverLegendCov { padding-left: 10px; padding-right: 10px; padding-bottom: 2px; background-color: #cad7fe; } /* Source code view: format for lines which were not executed */ td.lineNoCov, span.lineNoCov { background-color: #ff6230; } /* Source code view: format for NoCov legend */ span.coverLegendNoCov { padding-left: 10px; padding-right: 10px; padding-bottom: 2px; background-color: #ff6230; } /* Source code view (function table): standard link - visited format */ td.lineNoCov > a:visited, td.lineCov > a:visited { color: #000000; text-decoration: underline; } /* Source code view: format for lines which were executed only in a previous version */ span.lineDiffCov { background-color: #b5f7af; } /* Source code view: format for branches which were executed * and taken */ span.branchCov { background-color: #cad7fe; } /* Source code view: format for branches which were executed * but not taken */ span.branchNoCov { background-color: #ff6230; } /* Source code view: format for branches which were not executed */ span.branchNoExec { background-color: #ff6230; } /* Source code view: format for the source code heading line */ pre.sourceHeading { white-space: pre; font-family: monospace; font-weight: bold; margin: 0px; } /* All views: header legend value for low rate */ td.headerValueLegL { text-align: center; white-space: nowrap; padding-left: 4px; padding-right: 2px; background-color: #ff0000; font-size: 80%; } /* All views: header legend value for med rate */ td.headerValueLegM { text-align: center; white-space: nowrap; padding-left: 2px; padding-right: 2px; background-color: #ffea20; font-size: 80%; } /* All views: header legend value for hi rate */ td.headerValueLegH { text-align: center; white-space: nowrap; padding-left: 2px; padding-right: 4px; background-color: #a7fc9d; font-size: 80%; } /* All views except source code view: legend format for low coverage */ span.coverLegendCovLo { padding-left: 10px; padding-right: 10px; padding-top: 2px; background-color: #ff0000; } /* All views except source code view: legend format for med coverage */ span.coverLegendCovMed { padding-left: 10px; padding-right: 10px; padding-top: 2px; background-color: #ffea20; } /* All views except source code view: legend format for hi coverage */ span.coverLegendCovHi { padding-left: 10px; padding-right: 10px; padding-top: 2px; background-color: #a7fc9d; } ================================================ FILE: .github/scripts/indexgen/dashboard-styles/main.css ================================================ [data-md-color-scheme="slate"] { --md-hue: 218; --md-default-bg-color: hsla(var(--md-hue), 22%, 7%, 1); } [data-md-color-primary="teal"] { --md-primary-fg-color: #25292e; } [data-md-color-scheme="slate"][data-md-color-primary="teal"] { --md-typeset-a-color: #00d0c9; } .md-social { display: none; } .md-header__option { display: none; } ================================================ FILE: .github/scripts/indexgen/generate.py ================================================ #!/usr/bin/env python3 import argparse import os import shutil import logging import jinja2 # ============================================================================== def render_template(src, dst, **kwargs): """ Renders a jinja2 template file to another file """ with open(src, "r") as fp: tpl = jinja2.Template(fp.read()) with open(dst, "w") as fp: fp.write(tpl.render(**kwargs)) # ============================================================================== def make_coverage_report_index(branch, root, output, templates): """ Prepares coverage report index page """ logging.debug("=== make_coverage_report_index") logging.debug(f"branch = {branch}") logging.debug(f"root = {root}") logging.debug(f"output = {output}") logging.debug(f"templates = {templates}") logging.debug("===") keys = ["all", "branch", "toggle", "functional"] path = os.path.join(root, "coverage_dashboard") # Collect summary reports summary = {k: None for k in keys} for key in keys: file = key fname = os.path.join(path, file) if os.path.isdir(fname): summary[key] = file # Collect individual test reports individual = {k: dict() for k in keys} for key in keys: pfx = key + "_" if not os.path.isdir(path): continue for file in sorted(os.listdir(path)): fname = os.path.join(path, file) if not os.path.isdir(fname): continue if not file.startswith(pfx): continue # Extract test name test_name = file[len(pfx):] # Append the report individual[key][test_name] = file # Render the template params = { "ref": branch + "_coverage_dashboard", "summary": summary, "individual": individual, } os.makedirs(output, exist_ok=True) render_template( os.path.join(templates, "coverage_dashboard.md"), os.path.join(output, "coverage_dashboard.md"), **params ) def make_verification_report_index(branch, root, output, templates): """ Prepares verification tests report index page """ logging.debug("=== make_verification_report_index") logging.debug(f"branch = {branch}") logging.debug(f"root = {root}") logging.debug(f"output = {output}") logging.debug(f"templates = {templates}") logging.debug("===") path = os.path.join(root, "verification_dashboard") # Collect tests tests = set() if os.path.isdir(path): for file in sorted(os.listdir(path)): if not file.startswith("webpage_"): continue test_name = file.replace("webpage_", "") tests.add(test_name) # Render the template params = { "ref": branch + "_verification_dashboard", "tests": tests, } os.makedirs(output, exist_ok=True) render_template( os.path.join(templates, "verification_dashboard.md"), os.path.join(output, "verification_dashboard.md"), **params ) def make_dev_index(branches, output, templates): """ Prepares the branch/pr index page """ logging.debug("=== make_dev_index") logging.debug(f"branches = {branches}") logging.debug(f"output = {output}") logging.debug(f"templates = {templates}") logging.debug("===") params = { "branches": branches, } render_template( os.path.join(templates, "dev.md"), os.path.join(output, "dev.md"), **params ) # ============================================================================== def main(): logging.basicConfig(encoding="utf-8", level=logging.DEBUG) # Parse args parser = argparse.ArgumentParser() parser.add_argument( "--template", type=str, required=True, help="Templates path", ) parser.add_argument( "--root", type=str, default=None, help="Existing webpage root path", ) parser.add_argument( "--output", type=str, required=True, help="Output path", ) args = parser.parse_args() # Check if os.path.abspath(args.root) == os.path.abspath(args.output): print("Error: Existing webpage root and output paths mustn't be the same") exit(-1) # Reports for the main branch make_coverage_report_index( "main", os.path.join(args.root, "main"), os.path.join(args.output, "main"), args.template ) make_verification_report_index( "main", os.path.join(args.root, "main"), os.path.join(args.output, "main"), args.template ) # Reports for development branches / pull requests branches = [] path = os.path.join(args.root, "dev") if os.path.isdir(path): for file in os.listdir(path): if not os.path.isdir(os.path.join(path, file)): continue branches.append(file) make_coverage_report_index( file, os.path.join(args.root, "dev", file), os.path.join(args.output, "dev", file), args.template ) make_verification_report_index( file, os.path.join(args.root, "dev", file), os.path.join(args.output, "dev", file), args.template ) # Prepare the branch/pr index page make_dev_index(branches, args.output, args.template) # Copy other files/pages files = [ "conf.py", "main.md", "index.md", ] for file in files: shutil.copy( os.path.join(args.template, file), os.path.join(args.output, file), ) if __name__ == "__main__": main() ================================================ FILE: .github/scripts/indexgen/index_redirect/index.html ================================================ ================================================ FILE: .github/scripts/indexgen/requirements.txt ================================================ myst-parser sphinx sphinx_tabs sphinxcontrib-mermaid https://github.com/antmicro/sphinx-immaterial/releases/download/tip/sphinx_immaterial-0.0.post1.tip-py3-none-any.whl https://github.com/antmicro/antmicro-sphinx-utils/archive/main.zip jinja2 ================================================ FILE: .github/scripts/indexgen/source.template/conf.py ================================================ # -*- coding: utf-8 -*- # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this file. # # All configuration values have a default; values that are commented out # serve to show the default. # # Updated documentation of the configuration options is available at # https://www.sphinx-doc.org/en/master/usage/configuration.html from datetime import datetime from antmicro_sphinx_utils.defaults import ( numfig_format, extensions as default_extensions, myst_enable_extensions as default_myst_enable_extensions, antmicro_html, ) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # General information about the project. project = u'RISC-V VeeR-EL2 Core' basic_filename = u'veer-test-reports' authors = u'CHIPS Alliance' copyright = f'{authors}, {datetime.now().year}' # The short X.Y version. version = '' # The full version, including alpha/beta/rc tags. release = '' # This is temporary before the clash between myst-parser and immaterial is fixed sphinx_immaterial_override_builtin_admonitions = False numfig = True # If you need to add extensions just add to those lists extensions = default_extensions myst_enable_extensions = default_myst_enable_extensions myst_substitutions = { "project": project } myst_url_schemes = { "http": None, "https": None, "external": "{{path}}", } today_fmt = '%Y-%m-%d' todo_include_todos=False # -- Options for HTML output --------------------------------------------------- html_theme = 'sphinx_immaterial' html_last_updated_fmt = today_fmt html_show_sphinx = False ( html_logo, html_theme_options, html_context ) = antmicro_html() html_theme_options["palette"][0].update({ "scheme": "slate", "primary": "teal", "accent": "white", }) # # Disable toggle theme button # html_theme_options = { # "palette": [] # } html_title = project def setup(app): app.add_css_file('main.css') ================================================ FILE: .github/scripts/indexgen/source.template/coverage_dashboard.md ================================================ ({{ ref }})= # Coverage dashboard ## Summary reports (all tests) {%- for coverage in summary %} {%- if summary[coverage] %} * [{{ coverage }} coverage](external:coverage_dashboard/{{ summary[coverage] }}/index.html) {%- else %} * {{ coverage }} coverage (no data) {%- endif %} {%- endfor %} ## Individual test reports {%- for coverage in individual %} ### {{ coverage }} coverage {%- if individual[coverage] %} {%- for test in individual[coverage] %} * [{{ test }}](external:coverage_dashboard/{{ individual[coverage][test] }}/index.html) {%- endfor %} {%- else %} no data {%- endif %} {%- endfor %} ================================================ FILE: .github/scripts/indexgen/source.template/dev.md ================================================ # Active pull requests {%- for branch in branches %} * {{ branch }} * [Coverage]({{ branch }}_coverage_dashboard) * [Verification tests]({{ branch }}_verification_dashboard) * [Documentation](external:dev/{{ branch }}/docs_rendered/html/index.html) {%- endfor %} ================================================ FILE: .github/scripts/indexgen/source.template/index.md ================================================ # {{ project }} ```{toctree} :maxdepth: 2 main dev ``` ================================================ FILE: .github/scripts/indexgen/source.template/main.md ================================================ # Main branch * [Coverage](main_coverage_dashboard) * [Verification tests](main_verification_dashboard) * [Documentation](external:main/docs_rendered/html/index.html) ================================================ FILE: .github/scripts/indexgen/source.template/verification_dashboard.md ================================================ ({{ ref }})= # Verification tests dashboard ## Test reports {%- for test in tests %} * [{{ test }}](external:verification_dashboard/webpage_{{ test }}/{{ test }}.html) {%- endfor %} * [RISCOF tests report](external:verification_dashboard/riscof/report.html) ================================================ FILE: .github/scripts/indexgen/update_styles.sh ================================================ #!/bin/bash SELF_DIR="$(dirname $(readlink -f ${BASH_SOURCE[0]}))" . ${SELF_DIR}/../common.inc.sh update_styles(){ # Update styles for sphinx theme and LCOV reports # Args: # BUILDDIR - path to where the webpage is made BUILD_DIR=$1 echo -e "${COLOR_WHITE}========== Update styles =========${COLOR_CLEAR}" echo -e "${COLOR_WHITE} BUILD_DIR = ${BUILD_DIR}${COLOR_CLEAR}" # Replace styles for sphinx build cp dashboard-styles/main.css ${BUILD_DIR}/html/_static/ # Add CHIPs logo cp dashboard-styles/assets/chips-alliance-logo-mono.svg ${BUILD_DIR}/html/_static/white.svg # Replace undesired CSS and progress bar sprites with desired style for LCOV reports copy_files(){ check_args_count $# 2 SOURCE=$1 SEARCH=$2 FILES=`find ${BUILD_DIR}/ -name ${SEARCH}` for FILE in ${FILES}; do echo "Copy ${SOURCE} to ${FILE}" cp $SOURCE $FILE done } CHIPS_GCOV_CSS=dashboard-styles/gcov.css AMBER=dashboard-styles/assets/amber.png RUBY=dashboard-styles/assets/ruby.png SNOW=dashboard-styles/assets/snow.png EMERALD=dashboard-styles/assets/emerald.png for ASSET in $CHIPS_GCOV_CSS $AMBER $RUBY $SNOW $EMERALD; do echo -e "${COLOR_WHITE}========== $ASSET =========${COLOR_CLEAR}" copy_files $ASSET $(basename "$ASSET") done echo -e "${COLOR_WHITE}Update styles ${COLOR_GREEN}SUCCEEDED${COLOR_CLEAR}" echo -e "${COLOR_WHITE}==========================${COLOR_CLEAR}" } # Example usage # BUILD_DIR=./build # update_styles.sh $BUILD_DIR check_args_count $# 1 update_styles "$@" ================================================ FILE: .github/scripts/info_process_setup.sh ================================================ #!/bin/bash set -ex apt update apt install -y git pipx # By default pipx uses `/root/.local/bin` which isn't in PATH. export PIPX_BIN_DIR=/usr/local/bin pipx install git+https://github.com/antmicro/info-process@1d1fa64f ================================================ FILE: .github/scripts/mapfile ================================================ map el2_exu_alu_ctl el2_exu_alu_ctl_wrapper.alu tb_top.rvtop_wrapper.rvtop.veer.exu.i_alu map el2_exu_mul_ctl el2_exu_mul_ctl_wrapper.mul tb_top.rvtop_wrapper.rvtop.veer.exu.i_mul map el2_exu_div_ctl el2_exu_div_ctl_wrapper.div tb_top.rvtop_wrapper.rvtop.veer.exu.i_div map dmi_jtag_to_core_sync dmi_test_wrapper.wrapper.i_dmi_jtag_to_core_sync tb_top.rvtop_wrapper.rvtop.dmi_wrapper.i_dmi_jtag_to_core_sync map rvjtag_tap dmi_test_wrapper.wrapper.i_jtag_tap tb_top.rvtop_wrapper.rvtop.dmi_wrapper.i_jtag_tap map el2_ifu_iccm_mem el2_ifu_iccm_mem_wrapper.mem tb_top.rvtop_wrapper.rvtop.mem.iccm.iccm map el2_lsu_dccm_mem el2_lsu_dccm_mem_wrapper.mem tb_top.rvtop_wrapper.rvtop.mem.Gen_dccm_enable.dccm map el2_ifu_compress_ctl el2_ifu_compress_ctl tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0 map el2_pic_ctrl el2_pic_ctrl tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst map el2_pmp el2_pmp_wrapper.pmp tb_top.rvtop_wrapper.rvtop.veer.pmp map el2_dec_ib_ctl el2_dec_ib_ctl_wrapper.tu tb_top.rvtop_wrapper.rvtop.veer.dec.instbuff map el2_dec_trigger el2_dec_trigger_wrapper.tu tb_top.rvtop_wrapper.rvtop.veer.dec.dec_trigger map el2_dma_ctrl el2_dma_ctrl tb_top.rvtop_wrapper.rvtop.veer.dma_ctrl map dmi_mux dmi_test_wrapper.mux tb_top.rvtop_wrapper.rvtop.dmi_mux map dmi_wrapper dmi_test_wrapper.wrapper tb_top.rvtop_wrapper.rvtop.dmi_wrapper map el2_configurable_gw 'el2_pic_ctrl.IO_CLK_GRP[0].GW[1].gw_inst' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.IO_CLK_GRP[0].GW[1].gw_inst' map el2_configurable_gw 'el2_pic_ctrl.IO_CLK_GRP[0].GW[2].gw_inst' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.IO_CLK_GRP[0].GW[2].gw_inst' map el2_configurable_gw 'el2_pic_ctrl.IO_CLK_GRP[0].GW[3].gw_inst' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.IO_CLK_GRP[0].GW[3].gw_inst' map el2_configurable_gw 'el2_pic_ctrl.IO_CLK_GRP[1].GW[0].gw_inst' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.IO_CLK_GRP[1].GW[0].gw_inst' map el2_configurable_gw 'el2_pic_ctrl.IO_CLK_GRP[1].GW[1].gw_inst' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.IO_CLK_GRP[1].GW[1].gw_inst' map el2_configurable_gw 'el2_pic_ctrl.IO_CLK_GRP[1].GW[2].gw_inst' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.IO_CLK_GRP[1].GW[2].gw_inst' map el2_configurable_gw 'el2_pic_ctrl.IO_CLK_GRP[1].GW[3].gw_inst' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.IO_CLK_GRP[1].GW[3].gw_inst' map el2_cmp_and_mux 'el2_pic_ctrl.genblock.LEVEL[0].COMPARE[0].cmp_l1' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.genblock.LEVEL[0].COMPARE[0].cmp_l1' map el2_cmp_and_mux 'el2_pic_ctrl.genblock.LEVEL[0].COMPARE[1].cmp_l1' 'tb_top.rvtop_wrapper.rvtop.veer.pic_ctrl_inst.genblock.LEVEL[0].COMPARE[1].cmp_l1' ================================================ FILE: .github/scripts/openocd/board/caliptra-verilator-rst.cfg ================================================ source [find sim-jtagdpi.cfg] source [find veer-el2-rst.cfg] # Increase timeouts in simulation riscv set_command_timeout_sec 300 ================================================ FILE: .github/scripts/openocd/board/caliptra-verilator.cfg ================================================ source [find sim-jtagdpi.cfg] source [find veer-el2.cfg] # Increase timeouts in simulation riscv set_command_timeout_sec 300 ================================================ FILE: .github/scripts/openocd/sim-jtagdpi.cfg ================================================ # Copyright lowRISC contributors. # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # "JTAG adapter" for simulation, exposed to OpenOCD through a TCP socket # speaking the remote_bitbang protocol. The adapter is implemented as # SystemVerilog DPI module. adapter driver remote_bitbang remote_bitbang port 5000 remote_bitbang host localhost ================================================ FILE: .github/scripts/openocd/veer-el2-rst.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME riscv } jtag newtap $_CHIPNAME tap -irlen 5 set _TARGETNAME $_CHIPNAME.tap target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME -rtos hwthread # Configure work area in on-chip SRAM $_TARGETNAME.0 configure -work-area-phys 0x50001000 -work-area-size 0x1000 -work-area-backup 0 # Mem access mode riscv set_mem_access sysbus # The following commands disable target examination and set explicitly the # core parameters read from CSRs. These required a modified version of # OpenOCD from https://github.com/antmicro/openocd/tree/riscv-nohalt riscv set_nohalt on riscv set_xlen 32 riscv set_misa 0x40001104 # Be verbose about GDB errors gdb_report_data_abort enable gdb_report_register_access_error enable # Always use hardware breakpoints. gdb_breakpoint_override hard ================================================ FILE: .github/scripts/openocd/veer-el2.cfg ================================================ if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME } else { set _CHIPNAME riscv } jtag newtap $_CHIPNAME tap -irlen 5 set _TARGETNAME $_CHIPNAME.tap target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME -rtos hwthread # Configure work area in on-chip SRAM $_TARGETNAME.0 configure -work-area-phys 0x50001000 -work-area-size 0x1000 -work-area-backup 0 $_TARGETNAME.0 configure -event gdb-detach { resume } $_TARGETNAME.0 riscv expose_csrs 1968=dcsr $_TARGETNAME.0 riscv expose_csrs 1969=dpc $_TARGETNAME.0 riscv expose_csrs 1988=dmst $_TARGETNAME.0 riscv expose_csrs 1992=dicawics $_TARGETNAME.0 riscv expose_csrs 1996=dicad0h $_TARGETNAME.0 riscv expose_csrs 1993=dicad0 $_TARGETNAME.0 riscv expose_csrs 1994=dicad1 $_TARGETNAME.0 riscv expose_csrs 1995=dicago proc write_icache_line {dicawics_ dicad0_ dicad0h_ dicad1_} { # 1. Write dicawics reg csr_dicawics $dicawics_ # 2. Write instruction data to dicad0 and dicad0h, and parity to dicad1 reg csr_dicad0 $dicad0_ reg csr_dicad0h $dicad0h_ reg csr_dicad1 $dicad1_ # 3. Write 1 to dicago to trigger Icache write operation reg csr_dicago 1 } proc read_icache_line {dicawics_} { # 1. Write dicawics reg csr_dicawics $dicawics_ # 2. Read to dicago to trigger Icache read operation reg csr_dicago # 3. get line chunk from dicad0 and dicad0h, and parity from dicad1 reg csr_dicad0 reg csr_dicad0h reg csr_dicad1 } proc write_icache_tag {dicawics_ dicad0_ dicad1_} { # 1. Write dicawics reg csr_dicawics $dicawics_ # 2. Write tag, valid, LRU information to dicad0, and parity to dicad1 reg csr_dicad0 $dicad0_ reg csr_dicad1 $dicad1_ # 3. Write 1 to dicago to trigger Icache write operation reg csr_dicago 1 } proc read_icache_tag {dicawics_} { # 1. Write dicawics reg csr_dicawics $dicawics_ # 2. Read to dicago to trigger Icache read operation reg csr_dicago # 3. get tag from dicad0, and parity from dicad1 reg csr_dicad0 reg csr_dicad1 } $_TARGETNAME.0 configure -event halted { echo "Starting ICache line read" # dicawics: array=0 way=1 index=1 set dicawics_value [expr {(0 << 24) | (1 << 20) | (1 << 5)}] read_icache_line $dicawics_value echo "Starting ICache line write" # Write instruction data to dicad0 and dicad0h set dicad0_value 0x30c00 set dicad0h_value 0xc00c0 # Write wrong parity to trigger error set dicad1_value 0xffffaaaa # iterate to perform write for many values of index for {set index 0} {$index < 5} {incr index} { # dicawics: array=0 way=1 set dicawics_value [expr {(0 << 24) | (1 << 20) | ($index << 5)}] write_icache_line $dicawics_value $dicad0_value $dicad0h_value $dicad1_value } echo "Starting ICache tag and status read" read_icache_tag $dicawics_value echo "Starting ICache tag and status write" # Write tag, valid, LRU information are in dicad0, parity is in dicad1 set dicad0_value 0xfcb set dicad1_value 0xffffffff for {set index 0} {$index < 5} {incr index} { # dicawics: array=1 way=1 set dicawics_value [expr {(1 << 24) | (1 << 20) | ($index << 5)}] write_icache_tag $dicawics_value $dicad0_value $dicad1_value } echo "ICache test done." } # Mem access mode riscv set_mem_access abstract # Be verbose about GDB errors gdb_report_data_abort enable gdb_report_register_access_error enable # Always use hardware breakpoints. gdb_breakpoint_override hard ================================================ FILE: .github/scripts/openocd_test.sh ================================================ #!/bin/bash # SPDX-License-Identifier: Apache-2.0 # Copyright 2024 Antmicro # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script runs Verilator RTL simulation in background and invokes OpenOCD # to perform JTAG access test SIM_LOG=`realpath sim.log` OPENOCD_LOG=`realpath openocd.log` set +e if [ "$#" -lt 1 ]; then echo "Usage: openocd_test.sh [openocd args ...]" exit 1 fi OPENOCD_ARGS=$@ # Utils source `dirname ${BASH_SOURCE[0]}`/utils.sh print_logs () { echo -e "${COLOR_WHITE}======== Simulation log ========${COLOR_OFF}" cat ${SIM_LOG} || true echo -e "${COLOR_WHITE}======== OpenOCD log ========${COLOR_OFF}" cat ${OPENOCD_LOG} || true } echo -e "${COLOR_WHITE}======== Launching interactive simulation ========${COLOR_OFF}" # Start the simulation echo -e "Starting simulation..." if [ -f obj_dir/Vtb_top ]; then SIM_START_STRING="VerilatorTB: Start of sim" obj_dir/Vtb_top >"${SIM_LOG}" 2>&1 & elif [ -f ./simv ]; then SIM_START_STRING=" remote_bitbang_port 5000" ./simv +vcs+lic+wait -cm line+cond+fsm+tgl+branch >"${SIM_LOG}" 2>&1 & else echo "No simulation binary found, exiting" exit 1 fi SIM_PID=$! # Wait wait_for_phrase "${SIM_LOG}" "${SIM_START_STRING}" if [ $? -ne 0 ]; then echo -e "${COLOR_RED}Failed to start the simulation!${COLOR_OFF}" print_logs terminate ${SIM_PID}; exit -1 fi echo -e "Simulation running and ready (pid=${SIM_PID})" # Wait a bit sleep 2s # Run the test echo -e "${COLOR_WHITE}======== Running OpenOCD test '$@' ========${COLOR_OFF}" cd ${RV_ROOT}/testbench/openocd_scripts && openocd -d2 ${OPENOCD_ARGS} >"${OPENOCD_LOG}" 2>&1 EXITCODE=$? if [ ${EXITCODE} -eq 0 ]; then echo -e "${COLOR_GREEN}[PASSED]${COLOR_OFF}" else echo -e "${COLOR_RED}[FAILED]${COLOR_OFF}" fi # Display logs print_logs wait $SIM_PID # Honor the exitcode exit ${EXITCODE} ================================================ FILE: .github/scripts/peripheral_access.tcl ================================================ # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # init set script_dir [file dirname [info script]] source [file join $script_dir common.tcl] # Manually read dmstatus and check if the core is actually held in external # reset. In the expected state bits anyunavail allrunning anyrunning allhalted # and anyhalted should be cleared. set val [riscv dmi_read $dmstatus_addr] puts "dmstatus: $val" if { ($val & 0x00000F00) != 0 } { echo "The core is not held in reset!" shutdown error } echo "Accessing ECC..." set golden { 0x63707365 0x38342d33 0x3030312e 0x0 } set actual [ read_memory 0x10008000 32 4 phys ] if {[compare $actual $golden] != 0} { shutdown error } echo "Accessing HMAC..." set golden { 0x6163686d 0x61327368 0x3030322e 0x0 } set actual [ read_memory 0x10010000 32 4 phys ] if {[compare $actual $golden] != 0} { shutdown error } echo "Accessing SHA512..." set golden { 0x61327368 0x31322d35 0x3830302e 0x0 } set actual [ read_memory 0x10020000 32 4 phys ] if {[compare $actual $golden] != 0} { shutdown error } echo "Accessing SHA256..." set golden { 0x61327368 0x35362d32 0x3830312e 0x0 } set actual [ read_memory 0x10028000 32 4 phys ] if {[compare $actual $golden] != 0} { shutdown error } echo "Writing and reading DOE IV..." set golden { 0xCAFEBABA 0xDEADBEEF 0xD0ED0E00 } write_memory 0x10000000 32 $golden phys set actual [ read_memory 0x10000000 32 3 phys ] if {[compare $actual $golden] != 0} { shutdown error } # Success shutdown ================================================ FILE: .github/scripts/prepare_coverage_data.sh ================================================ #!/bin/bash set -eu set -o pipefail if [ -v CI ] then set -x apt update apt install -y xz-utils # XZ compresses .info files A LOT better than GZIP, e.g., 9.4MB vs 175MB. tar acf ${SIM}_coverage_single_data.tar.xz info_files_$SIM ls info_files_$SIM fi DB_COUNT=`ls info_files_$SIM | sed 's#_[^_]*.info##' | sort | uniq | wc -l` # Filter out lockstep and el2_regfile_if modules if DCLS tests are not enabled if [ -v DCLS_ENABLE ] then _filter_out='' else _filter_out='--filter-out (lockstep|el2_regfile_if)' fi # Source path transformations are needed before merging to have matching paths in `.desc` files. find info_files_$SIM -name '*.info' -exec info-process transform \ --strip-file-prefix '.*Cores-VeeR-EL2/' \ --filter 'design/' $_filter_out \ {} \; if [ $SIM = verilator ] then # Split branch and line before merging to have correct data in `.desc` files. for FILE in info_files_$SIM/*_branch.info do info-process extract --coverage-type line --output ${FILE%%_branch.info}_line.info $FILE info-process extract --coverage-type cond --output ${FILE%%_branch.info}_cond.info $FILE # Extract branch coverage last, so that it can happen in-place info-process extract --coverage-type branch --output $FILE $FILE done fi for TYPE in branch line toggle cond do _sort_opt='' _transform_extra_opts='' if [ $SIM = verilator ] && [ $TYPE = toggle ] then _sort_opt=--sort-brda-names _transform_extra_opts='--set-block-ids --add-two-way-toggles --add-missing-brda-entries' fi info-process merge --output coverage_${TYPE}_$SIM.info $_sort_opt \ --test-list tests_${TYPE}_$SIM.desc --test-list-strip coverage_,_$TYPE.info \ info_files_$SIM/*_$TYPE.info info-process transform --normalize-hit-counts $_transform_extra_opts coverage_${TYPE}_$SIM.info done rm -rf info_files_$SIM if [ -z "${GITHUB_HEAD_REF}" ]; then # We're in merge triggered run export BRANCH=$GITHUB_REF_NAME else # We're in PR triggered run export BRANCH=$GITHUB_HEAD_REF fi export COMMIT=$GITHUB_SHA # Add config.json template, "datasets" will be generated by info-process. cat <config.json { "title": "VeeR EL2 coverage dashboard", "commit": "$COMMIT", "branch": "$BRANCH", "repo": "cores-veer-el2", "timestamp": "`date +"%Y-%m-%dT%H:%M:%S.%3N%z"`", "additional": { "db_count": "$DB_COUNT", "run_id": "$GITHUB_RUN_ID" } } END _out_dir=data_$SIM info-process pack --output $_out_dir --config config.json \ --coverage-files *_$SIM.info --description-files *_$SIM.desc rm config.json *_$SIM.info *_$SIM.desc # add logo cp docs/dashboard-styles/assets/chips-alliance-logo-mono.svg $_out_dir/logo.svg cat $_out_dir/config.json echo "Coverage data ready to be packaged in $PWD/$_out_dir" ================================================ FILE: .github/scripts/pytest/bar.html ================================================
back chips-alliance-logo test_pyuvm_branch.html
================================================ FILE: .github/scripts/pytest/css/styles.css ================================================ @import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap"); body { background-color: #0e1116; font-family: "Roboto", sans-serif; margin: 0; padding: 0; } body > *:not(:nth-child(3)) { max-width: 1520px; margin-left: auto; margin-right: auto; } body > input:first-of-type { margin-left: max(0px, (100% - 1520px) / 2); } h1, h2, span, p { color: #dfe1f1; font-size: 16px; } h1, h2 { font-size: 24px; font-weight: 500; margin-top: 75px; } a { color: #00d0c9; } .passed { color: #2fc36e; font-size: 14px; margin-left: 5px !important; } .xfailed, .skipped { color: #efac0a; font-size: 14px; margin-left: 5px !important; } .failed, .error, .xpassed { color: #f21e08; font-size: 14px; margin-left: 5px !important; } .col-name, .col-duration { color: #dfe1f1; font-size: 14px; } .sortable { color: #dfe1f1; font-size: 16px; } .log { background-color: #31363c; color: #dfe1f1; overflow: auto; } .bar { display: inline-flex; width: 100%; padding: 20px; align-items: center; background-color: #25292e; box-sizing: border-box; } .bar > .arrow { width: 30px; height: 30px; cursor: pointer; } .bar > .chip-alliance-link { position: absolute; left: max(150px, (100% - 1520px) / 2); } .bar > .title { position: absolute; left: 50%; transform: translateX(-50%); font-size: 20px; font-weight: 700; } #environment { color: #dfe1f1; width: 100%; } #environment tr:nth-child(odd) { background: none; } #environment td:first-child { width: 25%; } #results-table { color: #dfe1f1; } #yaml-table { color: #dfe1f1; } ================================================ FILE: .github/scripts/pytest/script/script.js ================================================ function previousPage() { window.history.back() } ================================================ FILE: .github/scripts/pytest/style_pytest_report.sh ================================================ #!/bin/bash SELF_DIR="$(dirname $(readlink -f ${BASH_SOURCE[0]}))" . ${SELF_DIR}/../common.inc.sh style_pytest_report(){ check_args_count $# 3 SRC_DIR=$1 DST_DIR=$2 HTML_FILE=$3 echo -e "${COLOR_WHITE}========== style_pytest_report =========${COLOR_CLEAR}" echo -e "${COLOR_WHITE} SRC_DIR = ${SRC_DIR}${COLOR_CLEAR}" echo -e "${COLOR_WHITE} DST_DIR = ${DST_DIR}${COLOR_CLEAR}" echo -e "${COLOR_WHITE} HTML_FILE = ${HTML_FILE}${COLOR_CLEAR}" # Copy assets mkdir -p ${DST_DIR}/assets cp ${SRC_DIR}/assets/* ${DST_DIR}/assets/ # Add bar above h1.title SEARCH="

" REPLACE=`cat ${SRC_DIR}/bar.html | tr '\n' ' '` REPLACE="$REPLACE $SEARCH" filename="${DST_DIR}/${HTML_FILE}" sed -i "s@$SEARCH@$REPLACE@" $filename # Copy JS script to build dir mkdir -p ${DST_DIR}/script cp -r ${SRC_DIR}/script/* ${DST_DIR}/script/ echo -e "${COLOR_WHITE}Style pytest report ${COLOR_GREEN}SUCCEEDED${COLOR_CLEAR}" echo -e "${COLOR_WHITE}========== style_pytest_report =========${COLOR_CLEAR}" } check_args_count $# 3 style_pytest_report "$@" ================================================ FILE: .github/scripts/requirements-coverage.txt ================================================ git+https://github.com/antmicro/sitespawner@abff708256a15a5db7c498ff7f484c78cf18d4e3 ================================================ FILE: .github/scripts/riscv_dv_matrix_include.py ================================================ from yaml import load, Loader from json import dumps from itertools import product import sys RISCV_DV_TESTS = ['riscv_arithmetic_basic_test'] if __name__ == "__main__": arg1 = sys.argv[1].strip() # Entries with pyflow for every RISCV_DV_TESTS. # These are included in `generate` job matrix but it's also a base for `run*` jobs. entries = [{ "test": test, "version": "pyflow", } for test in RISCV_DV_TESTS] # The argument passed needs to match the job name as variants are generated based on its matrix. if arg1.startswith('run'): with open('.github/workflows/test-riscv-dv.yml', 'rb') as fd: run_tests = load(fd, Loader=Loader)['jobs'][arg1] job_matrix = run_tests['strategy']['matrix'] # Replicate matrix entries for all variants based on the job's matrix keys and values. # # For example, if the matrix only has `test`, `version` and `iss` keys, and `iss` values # are `renode` and `spike`, then `entries` will be doubled after `key=iss` iteration as # each entry will be replaced by two entries: one with additional `iss: renode` argument # and the other with additional `iss: spike`. for key in job_matrix.keys(): if key in ['test', 'version', 'include', 'exclude']: continue entries = [{**entry, key: value} for entry, value in product(entries, job_matrix[key])] print(dumps(entries)) elif arg1 == 'generate': print(dumps(entries)) else: exit(1) ================================================ FILE: .github/scripts/riscv_dv_parse_testlist.py ================================================ import sys import os from json import dumps from yaml import load, Loader from typing import Generator RISCV_DV_HOME = "third_party/riscv-dv/" def parse_yaml(path: str) -> Generator[str, None, None]: with open(path, 'rb') as fd: tests = load(fd, Loader=Loader) for test in tests: if 'import' in test: import_path = test['import'].split('/', 1)[1] yield from parse_yaml(RISCV_DV_HOME + import_path) elif 'test' in test: yield test['test'] if __name__ == "__main__": if len(sys.argv) == 2: testlist = RISCV_DV_HOME + f'target/{sys.argv[1]}/testlist.yaml' # check if testlist.yaml is provided by RISCV-DV; if not - it's a # custom testlist file not provided by RISCV-DV by default; treat the # script argument as full a path if not os.path.isdir(testlist): testlist = sys.argv[1] testlist = parse_yaml(testlist) else: testlist = parse_yaml(RISCV_DV_HOME + 'yaml/base_testlist.yaml') testlist = list(testlist) # remove, will cause incomplete sim, need customized RTL testlist.remove("riscv_csr_test") print(dumps(testlist)) ================================================ FILE: .github/scripts/run_regression_test.sh ================================================ #!/bin/bash SELF_DIR="$(dirname $(readlink -f ${BASH_SOURCE[0]}))" . ${SELF_DIR}/common.inc.sh trap report_status EXIT report_status(){ rc=$? if [ $rc != 0 ]; then echo -e "${COLOR_WHITE}Test '${NAME}' ${COLOR_RED}FAILED${COLOR_CLEAR}" else mv ${DIR}/coverage.dat ${RESULTS_DIR}/ echo -e "${COLOR_WHITE}Test '${NAME}' ${COLOR_GREEN}SUCCEEDED${COLOR_CLEAR}" fi exit $rc } run_regression_test(){ # Run a regression test with coverage collection enabled # Args: # RESULTS_DIR - # BUS - # NAME - # COVERAGE - # USER_MODE - '1' for user mode, '0' for without user mode # CACHE WAYPACK - check_args_count $# 6 RESULTS_DIR=$1 BUS=$2 NAME=$3 COVERAGE=$4 USER_MODE=$5 ICACHE_WAYPACK=$6 echo -e "${COLOR_WHITE}========== running test '${NAME}' =========${COLOR_CLEAR}" echo -e "${COLOR_WHITE} RESULTS_DIR = ${RESULTS_DIR}${COLOR_CLEAR}" echo -e "${COLOR_WHITE} SYSTEM BUS = ${BUS}${COLOR_CLEAR}" echo -e "${COLOR_WHITE} NAME = ${NAME}${COLOR_CLEAR}" echo -e "${COLOR_WHITE} COVERAGE = ${COVERAGE}${COLOR_CLEAR}" echo -e "${COLOR_WHITE} USER_MODE = ${USER_MODE}${COLOR_CLEAR}" echo -e "${COLOR_WHITE} ICACHE_WAYPACK = ${ICACHE_WAYPACK}${COLOR_CLEAR}" COMMON_PARAMS="-set bitmanip_zba -set bitmanip_zbb -set bitmanip_zbc -set bitmanip_zbe -set bitmanip_zbf -set bitmanip_zbp -set bitmanip_zbr -set bitmanip_zbs -set=fpga_optimize=0" if [[ "${USER_MODE}" == "1" ]]; then COMMON_PARAMS="-set=user_mode=1 -set=smepmp=1 ${COMMON_PARAMS}" fi # DLCS_ENABLE may not be set set +u if [[ -z "${DCLS_ENABLE}" ]]; then DCLS_ENABLE="0" fi set -u if [[ "${DCLS_ENABLE}" == "1" ]]; then COMMON_PARAMS="-set lockstep_enable=1 -set lockstep_regfile_enable=1 ${COMMON_PARAMS}" fi COMMON_PARAMS="-set=icache_waypack=${ICACHE_WAYPACK} ${COMMON_PARAMS}" if [[ "${BUS}" == "axi" ]]; then PARAMS="-set build_axi4 ${COMMON_PARAMS}" elif [[ "${BUS}" == "ahb" ]]; then PARAMS="-set build_ahb_lite ${COMMON_PARAMS}" else echo -e "${COLOR_RED}Unknown system bus type '${BUS}'${COLOR_CLEAR}" exit 1 fi echo -e "${COLOR_WHITE} CONF PARAMS = ${PARAMS}${COLOR_CLEAR}" mkdir -p ${RESULTS_DIR} LOG="${RESULTS_DIR}/test_${NAME}_${COVERAGE}_${USER_MODE}.log" touch ${LOG} DIR="run_${NAME}_${COVERAGE}_${USER_MODE}" if [ "$NAME" = "pmp_random" ]; then EXTRA_ARGS='TB_MAX_CYCLES=8000000' else EXTRA_ARGS= fi # Run the test mkdir -p ${DIR} make -j`nproc` -C ${DIR} -f $RV_ROOT/tools/Makefile verilator $EXTRA_ARGS CONF_PARAMS="${PARAMS}" TEST=${NAME} COVERAGE=${COVERAGE} 2>&1 | tee ${LOG} } # Example usage # RESULTS_DIR=results # BUS=axi # NAME=hello_world # COVERAGE=branch # USER_MODE=1 # run_regression_test.sh $RESULTS_DIR $BUS $NAME $COVERAGE $USER_MODE check_args_count $# 6 run_regression_test "$@" ================================================ FILE: .github/scripts/run_regression_tests.sh ================================================ #!/bin/bash COLOR_CLEAR="\033[0m" COLOR_WHITE="\033[1;37m" COLOR_RED="\033[0;31m" COLOR_GREEN="\033[1;32m" RESULTS_DIR="results" mkdir -p ${RESULTS_DIR} # Configure VeeR echo -e "${COLOR_WHITE}==================== Configuring VeeR-EL2 core ====================${COLOR_CLEAR}" $RV_ROOT/configs/veer.config if [ $? -ne 0 ]; then echo "Failed to configure VeeR-EL2 core" exit -1 fi # Run regression tests with coverage collection enabled EXITCODE=0 TESTS=($TESTS) for NAME in ${TESTS[@]}; do echo -e "${COLOR_WHITE}==================== running test '${NAME}' ====================${COLOR_CLEAR}" for COVERAGE in branch toggle functional; do echo -e "${COLOR_WHITE}========== ${COVERAGE} coverage ==========${COLOR_CLEAR}" LOG="${RESULTS_DIR}/test_${NAME}_${COVERAGE}.log" DIR="run_${NAME}_${COVERAGE}" # Run the test mkdir -p ${DIR} make -j`nproc` -C ${DIR} -f $RV_ROOT/tools/Makefile verilator TEST=${NAME} COVERAGE=${COVERAGE} 2>&1 | tee ${LOG} RES=${PIPESTATUS[0]} if [ ${RES} -ne 0 ] || ! [ -f "${DIR}/coverage.dat" ]; then EXITCODE=-1 echo -e "${COLOR_WHITE}Test '${NAME}' ${COLOR_RED}FAILED${COLOR_CLEAR}" else # Copy and convert coverage data cp ${DIR}/coverage.dat ${RESULTS_DIR}/coverage_${NAME}_${COVERAGE}.dat verilator_coverage --write-info ${RESULTS_DIR}/coverage_${NAME}_${COVERAGE}.info ${RESULTS_DIR}/coverage_${NAME}_${COVERAGE}.dat echo -e "${COLOR_WHITE}Test '${NAME}' ${COLOR_GREEN}SUCCEEDED${COLOR_CLEAR}" fi done done exit ${EXITCODE} ================================================ FILE: .github/scripts/secrets_version ================================================ 3 ================================================ FILE: .github/scripts/test.gdb ================================================ # SPDX-License-Identifier: Apache-2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # echo Connecting to OpenOCD...\n set architecture riscv:rv32 set remotetimeout 360 target extended-remote :3333 echo Dumping registers...\n info registers echo Accessing region at 0x20000000...\n set *(0x20000000) = 0x01234567 set *(0x20000004) = 0x89ABCDEF set *(0x20000008) = 0x55555555 set *(0x2000000C) = 0xAAAAAAAA set *(0x25555550) = 0x55555555 set *(0x2aaaaaa0) = 0xAAAAAAAA print/x *0x20000000@4 print/x *0x25555550 print/x *0x2aaaaaa0 echo Accessing region at 0x30000000...\n set *(0x30000000) = 0x01234567 set *(0x30000004) = 0x89ABCDEF set *(0x30000008) = 0x55555555 set *(0x3000000C) = 0xAAAAAAAA set *(0x35555550) = 0x55555555 set *(0x3aaaaaa0) = 0xAAAAAAAA print/x *0x30000000@4 print/x *0x35555550 print/x *0x3aaaaaa0 echo Accessing region at 0x40000000...\n set *(0x40000000) = 0x01234567 set *(0x40000004) = 0x89ABCDEF set *(0x40000008) = 0x55555555 set *(0x4000000C) = 0xAAAAAAAA set *(0x45555550) = 0x55555555 set *(0x4aaaaaa0) = 0xAAAAAAAA print/x *0x40000000@4 print/x *0x45555550 print/x *0x4aaaaaa0 echo Accessing region at 0x50000000...\n set *(0x50000000) = 0x01234567 set *(0x50000004) = 0x89ABCDEF set *(0x50000008) = 0x55555555 set *(0x5000000C) = 0xAAAAAAAA set *(0x55555550) = 0x55555555 set *(0x5aaaaaa0) = 0xAAAAAAAA print/x *0x50000000@4 print/x *0x55555550 print/x *0x5aaaaaa0 echo Accessing region at 0x60000000...\n set *(0x60000000) = 0x01234567 set *(0x60000004) = 0x89ABCDEF set *(0x60000008) = 0x55555555 set *(0x6000000C) = 0xAAAAAAAA set *(0x65555550) = 0x55555555 set *(0x6aaaaaa0) = 0xAAAAAAAA print/x *0x60000000@4 print/x *0x65555550 print/x *0x6aaaaaa0 echo Accessing region at 0x70000000...\n set *(0x70000000) = 0x01234567 set *(0x70000004) = 0x89ABCDEF set *(0x70000008) = 0x55555555 set *(0x7000000C) = 0xAAAAAAAA set *(0x75555550) = 0x55555555 set *(0x7aaaaaa0) = 0xAAAAAAAA print/x *0x70000000@4 print/x *0x75555550 print/x *0x7aaaaaa0 echo Accessing region at 0x80000000...\n set *(0x80000000) = 0x01234567 set *(0x80000004) = 0x89ABCDEF set *(0x80000008) = 0x55555555 set *(0x8000000C) = 0xAAAAAAAA set *(0x85555550) = 0x55555555 set *(0x8aaaaaa0) = 0xAAAAAAAA print/x *0x80000000@4 print/x *0x85555550 print/x *0x8aaaaaa0 echo Accessing region at 0x90000000...\n set *(0x90000000) = 0x01234567 set *(0x90000004) = 0x89ABCDEF set *(0x90000008) = 0x55555555 set *(0x9000000C) = 0xAAAAAAAA set *(0x95555550) = 0x55555555 set *(0x9aaaaaa0) = 0xAAAAAAAA print/x *0x90000000@4 print/x *0x95555550 print/x *0x9aaaaaa0 echo Accessing region at 0xa0000000...\n set *(0xa0000000) = 0x01234567 set *(0xa0000004) = 0x89ABCDEF set *(0xa0000008) = 0x55555555 set *(0xa000000C) = 0xAAAAAAAA set *(0xa5555550) = 0x55555555 set *(0xaaaaaaa0) = 0xAAAAAAAA print/x *0xa0000000@4 print/x *0xa5555550 print/x *0xaaaaaaa0 echo Accessing region at 0xb0000000...\n set *(0xb0000000) = 0x01234567 set *(0xb0000004) = 0x89ABCDEF set *(0xb0000008) = 0x55555555 set *(0xb000000C) = 0xAAAAAAAA set *(0xb5555550) = 0x55555555 set *(0xbaaaaaa0) = 0xAAAAAAAA print/x *0xb0000000@4 print/x *0xb5555550 print/x *0xbaaaaaa0 echo Accessing region at 0xc0000000...\n set *(0xc0000000) = 0x01234567 set *(0xc0000004) = 0x89ABCDEF set *(0xc0000008) = 0x55555555 set *(0xc000000C) = 0xAAAAAAAA set *(0xc5555550) = 0x55555555 set *(0xcaaaaaa0) = 0xAAAAAAAA print/x *0xc0000000@4 print/x *0xc5555550 print/x *0xcaaaaaa0 echo Accessing region at 0xd0000000...\n set *(0xd0000000) = 0x01234567 set *(0xd0000004) = 0x89ABCDEF set *(0xd0000008) = 0x55555555 set *(0xd000000C) = 0xAAAAAAAA set *(0xd5555550) = 0x55555555 set *(0xdaaaaaa0) = 0xAAAAAAAA print/x *0xd0000000@4 print/x *0xd5555550 print/x *0xdaaaaaa0 echo Setting Breakpoint 1...\n hbreak *0x1c echo Continuing...\n continue delete # end the simulation gracefully set *(volatile unsigned char*)0xd0580000 = 0xff ================================================ FILE: .github/scripts/utils.sh ================================================ #!/bin/bash # SPDX-License-Identifier: Apache-2.0 # Copyright 2024 Antmicro # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Colors COLOR_OFF='\033[0m' COLOR_RED='\033[31m' COLOR_GREEN='\033[32m' COLOR_WHITE='\033[1;37m' # Waits until the given phrase appears in a log file (actively written to) # Usage: wait_for_phrase wait_for_phrase () { # Check if the log exists sleep 1s if ! [ -f "$1" ]; then echo -e "${COLOR_RED}Log file '$1' not found!${COLOR_OFF}" return -1 fi # Wait for the phrase DEADLINE=$(($(date +%s) + 30)) while [ $(date +%s) -lt ${DEADLINE} ] do # Check for the phrase grep "$2" "$1" >/dev/null if [ $? -eq 0 ]; then return 0 fi # Sleep and retry sleep 1s done # Timeout return -1 } # Terminates a process. First via SIGINT and if this doesn't work after 10s # retries with SIGKILL # Usage: terminate terminate () { local PID=$1 # Gently interrupt, wait some time and then kill /bin/kill -s SIGINT ${PID} || true sleep 10s /bin/kill -s SIGKILL ${PID} || true } ================================================ FILE: .github/workflows/build-docs.yml ================================================ name: Documentation build on: workflow_call: jobs: build: name: Build runs-on: ubuntu-24.04 env: DEBIAN_FRONTEND: "noninteractive" steps: - name: Install dependencies run: | sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ python3 python3-pip - name: Setup repository uses: actions/checkout@v4 - name: Build Docs run: | pushd docs pip3 install -r requirements.txt TZ=UTC make html popd ls -lah docs/build - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: docs path: ./docs/build ================================================ FILE: .github/workflows/ci.yml ================================================ name: VeeR-EL2 CI on: push: branches: ["main"] pull_request: workflow_dispatch: schedule: - cron: '0 2 * * *' # run daily at 02:00 am (UTC) jobs: Test-DCLS: name: Test-DCLS-Regression uses: ./.github/workflows/test-regression-dcls.yml Test-Regression-Cache-Waypack-0-num-ways-2: name: Test-Regression Cache Waypack 0 Num Ways 2 uses: ./.github/workflows/test-regression-cache-waypack.yml with: waypack: 0 num_ways: 2 Test-Regression-Cache-Waypack-0-num-ways-4: name: Test-Regression Cache Waypack 0 Num Ways 4 uses: ./.github/workflows/test-regression-cache-waypack.yml with: waypack: 0 num_ways: 4 Test-Regression-Cache-Waypack-1-num-ways-2: name: Test-Regression Cache Waypack 1 Num Ways 2 uses: ./.github/workflows/test-regression-cache-waypack.yml with: waypack: 1 num_ways: 2 Test-Regression-Cache-Waypack-1-num-ways-4: name: Test-Regression Cache Waypack 1 Num Ways 4 uses: ./.github/workflows/test-regression-cache-waypack.yml with: waypack: 1 num_ways: 4 Test-Exceptions-Regression: name: Test-Exceptions-Regression uses: ./.github/workflows/test-regression-exceptions.yml Test-Verification: name: Test-Verification uses: ./.github/workflows/test-verification.yml Test-Microarchitectural: name: Test-Microarchitectural uses: ./.github/workflows/test-uarch.yml Test-RISCV-DV: name: Test-RISCV-DV uses: ./.github/workflows/test-riscv-dv.yml Test-RISCOF: name: Test-RISCOF uses: ./.github/workflows/test-riscof.yml Test-UVM: name: Test-UVM uses: ./.github/workflows/test-uvm.yml Test-Renode: name: Test-Renode uses: ./.github/workflows/test-renode.yml Test-OpenOCD: name: Test-OpenOCD uses: ./.github/workflows/test-openocd.yml Report-Coverage: name: Report-Coverage needs: [ Test-DCLS, Test-Regression-Cache-Waypack-0-num-ways-2, Test-Regression-Cache-Waypack-0-num-ways-4, Test-Regression-Cache-Waypack-1-num-ways-2, Test-Regression-Cache-Waypack-1-num-ways-4, Test-Exceptions-Regression, Test-Verification, Test-Microarchitectural, Test-RISCV-DV, Test-RISCOF, Test-OpenOCD ] uses: ./.github/workflows/report-coverage.yml Build-Docs: name: Build-Docs uses: ./.github/workflows/build-docs.yml Publish-to-GH-Pages: concurrency: group: concurrency-group-${{ github.repository }}-publish cancel-in-progress: false permissions: actions: write contents: write name: Publish-to-GH-Pages needs: [Report-Coverage, Build-Docs] uses: ./.github/workflows/publish-webpage.yml ================================================ FILE: .github/workflows/custom-lint.yml ================================================ name: Custom lint on: push: branches: - main pull_request: jobs: run-lint: name: Run lint runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 env: GHA_EXTERNAL_DISK: additional-tools-all GHA_SA: gh-sa-veer-uploader steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Run lint run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_lint ================================================ FILE: .github/workflows/gh-pages-pr-closed.yml ================================================ name: GH-Pages PR Remove on: pull_request: types: - closed jobs: build: name: PR Remove concurrency: group: gh-pages runs-on: ubuntu-24.04 permissions: contents: write steps: - name: Save PR number run: | echo "number=${{ github.event.number }}" >> delete_pr_number.txt - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: delete_pr_number path: ./delete_pr_number.txt ================================================ FILE: .github/workflows/gh-pages-pr-comment.yml ================================================ name: GH-Pages PR Comment on: workflow_run: workflows: ["VeeR-EL2 CI"] types: - completed env: WEB_URL: 'https://chipsalliance.github.io/Cores-VeeR-EL2/' jobs: comment: name: PR Comment runs-on: ubuntu-24.04 permissions: pull-requests: write if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }} steps: - name: Download artifact id: download-artifact uses: dawidd6/action-download-artifact@v6 with: name: pr_number path: ./ run_id: ${{ github.event.workflow_run.id }} - name: Extract PR number id: PR run: | cat pr_number.txt | tee "$GITHUB_OUTPUT" - uses: actions/github-script@v6 with: script: | github.rest.issues.createComment({ issue_number: ${{ steps.PR.outputs.number }}, owner: context.repo.owner, repo: context.repo.repo, body: 'Coverage report for this PR is available at ${{ env.WEB_URL }}/html/dev/${{ steps.PR.outputs.number }}/coverage_dashboard/all, documentation is available at ${{ env.WEB_URL }}/html/dev/${{ steps.PR.outputs.number }}/docs_rendered/html' }) ================================================ FILE: .github/workflows/gh-pages-pr-remove.yml ================================================ name: GH-Pages PR Remove Deploy on: workflow_run: workflows: ["GH-Pages PR Remove"] types: - completed env: ROOT_DIR: './public.new' jobs: remove: name: PR Remove Deploy concurrency: group: gh-pages runs-on: ubuntu-24.04 permissions: contents: write steps: - name: Setup repository uses: actions/checkout@v4 - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt echo "PATH=$PATH" >> $GITHUB_ENV - name: Download deployment uses: actions/checkout@v4 with: ref: gh-pages path: ${{ env.ROOT_DIR }} - name: Download artifact id: download-artifact uses: dawidd6/action-download-artifact@v6 with: name: delete_pr_number path: ./ run_id: ${{ github.event.workflow_run.id }} - name: Extract PR number id: PR run: | cat delete_pr_number.txt | tee "$GITHUB_OUTPUT" rm -rf delete_pr_number.txt - name: Update the webpage run: | rm -rf ${{ env.ROOT_DIR }}/html/dev/${{ steps.PR.outputs.number }} rm -rf ${{ env.ROOT_DIR }}/doctrees/dev/${{ steps.PR.outputs.number }} - name: Add redirect index page run: | cp .github/scripts/indexgen/index_redirect/index.html ./public.new/ - name: Deploy uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./public.new commit_message: "Remove reports from PR#${{ steps.PR.outputs.number }}" force_orphan: true ================================================ FILE: .github/workflows/publish-webpage.yml ================================================ name: GH-Pages Build and Main Deploy on: workflow_call: jobs: build: name: Build and Main Deploy concurrency: group: gh-pages runs-on: ubuntu-24.04 container: image: debian:trixie permissions: contents: write steps: - name: Setup repository uses: actions/checkout@v4 - name: Print metadata run: | run_information="Repository: ${{ github.repository }} Commit SHA:${{ github.sha }} Workflow: ${{ github.workflow }} Run:${{ github.run_id }}" echo $run_information - name: Download coverage reports uses: actions/download-artifact@v4 with: name: data_verilator path: data_verilator/ - name: Download coverage reports merged uses: actions/download-artifact@v4 with: name: data_both path: data_both/ - name: Download docs uses: actions/download-artifact@v4 with: name: docs path: ./docs_rendered - name: Download verification reports uses: actions/download-artifact@v4 with: pattern: verification_dashboard* merge-multiple: true path: ./verification_dashboard - name: Download RISCOF report uses: actions/download-artifact@v4 with: pattern: riscof-report* merge-multiple: true path: ./riscof_dashboard - name: Checkout gh-pages uses: actions/checkout@v4 with: ref: gh-pages path: ./public.checkout - name: Preserve only valid items run: | mkdir -p ./public.new mv ./public.checkout/doctrees ./public.new/ | true mv ./public.checkout/html ./public.new/ | true - name: Update webpage run: | set -eux set -o pipefail apt -y update apt -y install nodejs npm python3 zip git echo "Event: $GITHUB_EVENT_NAME, ref: $GITHUB_REF_NAME)" if [ "$GITHUB_EVENT_NAME" = pull_request ] then TARGET_DIR="${PWD}/public.new/html/dev/${{ github.event.number }}" elif [ "$GITHUB_REF_NAME" = main ] then TARGET_DIR="${PWD}/public.new/html/main" else # Currently deploying is only possible in PRs and on main but let's # better keep things safe in case that's changed in the future by # using another target dir in other cases. TARGET_DIR="${PWD}/public.new/html/other" fi mkdir -p $TARGET_DIR # data cd data_verilator zip $TARGET_DIR/data.zip * cd ../data_both zip $TARGET_DIR/data_both.zip * cd .. # get coverview git clone https://github.com/antmicro/coverview cd coverview npm install npm run build python3 embed.py --inject-data $TARGET_DIR/data_both.zip cd .. # dashboard rm -rf $TARGET_DIR/coverage_dashboard* mkdir -p $TARGET_DIR/coverage_dashboard/all cp -a coverview/dist/* $TARGET_DIR/coverage_dashboard/all # docs rm -rf $TARGET_DIR/docs_rendered mkdir -p $TARGET_DIR/docs_rendered mv ./docs_rendered/* $TARGET_DIR/docs_rendered echo ${GITHUB_RUN_ID} > $TARGET_DIR/run_id tar -acf webpage.tar.gz public.new - name: Add redirect index page run: | cp .github/scripts/indexgen/index_redirect/index.html ./public.new/ - name: Deploy uses: peaceiris/actions-gh-pages@v4 if: ${{ github.ref == 'refs/heads/main' || github.event_name == 'pull_request' }} with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./public.new force_orphan: true - name: Save PR number if: github.event_name == 'pull_request' run: | echo "number=${{ github.event.number }}" >> pr_number.txt - name: Upload artifacts uses: actions/upload-artifact@v4 if: github.event_name == 'pull_request' with: name: pr_number path: ./pr_number.txt - name: Pack webpage as an artifact if: always() uses: actions/upload-artifact@v4 with: name: webpage path: ./webpage.tar.gz ================================================ FILE: .github/workflows/report-coverage.yml ================================================ name: Coverage report on: workflow_call: defaults: run: shell: bash jobs: merge-verilator-reports: name: Merge Verilator info data runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 env: DEBIAN_FRONTEND: "noninteractive" steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Download coverage reports uses: actions/download-artifact@v4 with: pattern: "*coverage_data*" merge-multiple: true path: ./ - name: Setup info-process run: .github/scripts/info_process_setup.sh - name: Merge data run: | mkdir info_files_verilator mv *.info info_files_verilator/ export SIM=verilator .github/scripts/prepare_coverage_data.sh - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: verilator_coverage_single_data path: verilator_coverage_single_data.tar.xz - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: data_verilator path: data_verilator/* custom-coverage-reports: name: Custom coverage reports runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 env: GHA_EXTERNAL_DISK: additional-tools GHA_SA: gh-sa-veer-uploader steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Prepare Environment run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_prepare_env - name: Generate custom reports run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_custom_report - name: Pack artifacts uses: actions/upload-artifact@v4 with: name: info_files_v_mapped path: info_files_v/* both-coverage-reports: name: Coverage reports merger runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: debian:trixie needs: [merge-verilator-reports, custom-coverage-reports] env: DEBIAN_FRONTEND: noninteractive GHA_EXTERNAL_DISK: additional-tools GHA_SA: gh-sa-veer-uploader steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Extract custom coverage run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_extract_custom_coverage - name: Setup info-process run: .github/scripts/info_process_setup.sh - name: Prepare custom coverage run: | export SIM=v .github/scripts/prepare_coverage_data.sh # info_files_v_mapped uses the same dir. rm -rf info_files_v - name: Pack artifacts uses: actions/upload-artifact@v4 with: name: v_coverage_single_data path: v_coverage_single_data.tar.xz - name: Pack artifacts uses: actions/upload-artifact@v4 with: name: data_v path: data_v/* - name: Download Verilator data uses: actions/download-artifact@v4 with: name: data_verilator path: data_verilator/ - name: Compare tests run: | cat data_v/*.desc | grep '^TEST:' | sed 's#.*,##' | sed 's#;#\n#g' | sort | uniq >tests_v cat data_verilator/*.desc | grep '^TEST:' | sed 's#.*,##' | sed 's#;#\n#g' | sort | uniq >tests_verilator # `|| true` because it's only needed for informational purposes, a difference is not a reason to fail. diff -yt tests_v tests_verilator || true - name: Create merged package run: | .github/scripts/create_merged_package.sh rm -rf data_verilator rm -rf data_v - name: Pack artifacts uses: actions/upload-artifact@v4 with: name: data_both path: data_both/* - name: Download V mapped info files uses: actions/download-artifact@v4 with: name: info_files_v_mapped path: info_files_v - name: Prepare custom coverage run: | export SIM=v .github/scripts/prepare_coverage_data.sh - name: Pack artifacts uses: actions/upload-artifact@v4 with: name: data_v_mapped path: data_v/* ================================================ FILE: .github/workflows/test-openocd.yml ================================================ name: Test-OpenOCD on: workflow_call: defaults: run: shell: bash jobs: tests: name: Run OpenOCD tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 strategy: fail-fast: false matrix: coverage: ["all"] bus: ["axi4", "ahb_lite"] env: DEBIAN_FRONTEND: "noninteractive" CCACHE_DIR: "/opt/openocd-tests/.cache/" steps: - name: Install utils run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null echo "debconf debconf/frontend select Noninteractive" | sudo debconf-set-selections sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ ccache ninja-build gcc-riscv64-unknown-elf pip3 install meson wget https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2024.09.03/riscv64-elf-ubuntu-22.04-gcc-nightly-2024.09.03-nightly.tar.gz tar -xzf riscv64-elf-ubuntu-22.04-gcc-nightly-2024.09.03-nightly.tar.gz mv riscv /opt/ - name: Setup Cache Metadata id: cache_metadata run: | date=$(date +"%Y_%m_%d") time=$(date +"%Y%m%d_%H%M%S_%N") cache_test_restore_key=${{ matrix.coverage }}_ cache_test_key=${cache_test_restore_key}${time} echo "date=$date" | tee -a "$GITHUB_ENV" echo "time=$time" | tee -a "$GITHUB_ENV" echo "cache_test_restore_key=$cache_test_restore_key" | tee -a "$GITHUB_ENV" echo "cache_test_key=$cache_test_key" | tee -a "$GITHUB_ENV" - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt echo "PATH=$PATH" >> $GITHUB_ENV - name: Build verilated simulation run: | export PATH=/opt/verilator/bin:/opt/openocd/bin:$PATH export RV_ROOT=$(pwd) mkdir run make -C run -f ${RV_ROOT}/tools/Makefile verilator-build program.hex TEST=infinite_loop \ CONF_PARAMS="-set build_${{ matrix.bus }} -set openocd_test" COVERAGE=${{ matrix.coverage }} -j$(nproc) cd run ${RV_ROOT}/.github/scripts/openocd_test.sh \ -f ${RV_ROOT}/testbench/openocd_scripts/verilator-rst.cfg \ -f ${RV_ROOT}/testbench/openocd_scripts/jtag_cg.tcl pkill openocd || true - name: Test with GDB-test (register access, memory access, breakpoints) run: | # TODO GDB is in /opt/riscv and a separate toolchain is installed with apt. Make this better. export PATH=/opt/riscv/bin:/opt/verilator/bin:/opt/openocd/bin:$PATH export RV_ROOT=$(pwd) mkdir gdb_test make -C gdb_test -f ${RV_ROOT}/tools/Makefile verilator-build program.hex TEST=infinite_loop \ CONF_PARAMS="-set build_${{ matrix.bus }} -set openocd_test" COVERAGE=${{ matrix.coverage }} -j$(nproc) cd gdb_test ${RV_ROOT}/.github/scripts/gdb_test.sh pkill openocd || true - name: Prepare coverage data run: | export PATH=/opt/verilator/bin:$PATH export RV_ROOT=$(pwd) mkdir -p results if [ ${{ matrix.bus }} = axi4 ]; then BUS_NAME=axi elif [ ${{ matrix.bus }} = ahb_lite ]; then BUS_NAME=ahb fi .github/scripts/convert_dat.sh ${RV_ROOT}/run/coverage.dat \ results/coverage_${BUS_NAME}-openocd .github/scripts/convert_dat.sh ${RV_ROOT}/gdb_test/coverage.dat \ results/coverage_${BUS_NAME}-openocd-gdb - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: openocd_coverage_data_${{ matrix.bus }}_${{ matrix.coverage }} path: results/*.info custom-openocd-tests: name: Run Custom OpenOCD tests runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 strategy: fail-fast: false matrix: bus: ["axi4"] env: GHA_EXTERNAL_DISK: additional-tools GHA_SA: gh-sa-veer-uploader steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Run tests run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_custom_openocd_tests BUS: ${{ matrix.bus }} ================================================ FILE: .github/workflows/test-regression-cache-waypack.yml ================================================ name: Regression tests cache waypack on: workflow_call: inputs: waypack: required: true type: number num_ways: required: true type: number defaults: run: shell: bash env: WAYPACK: ${{ inputs.waypack }} NUM_WAYS: ${{ inputs.num_ways }} jobs: regression-tests: name: Regression tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 strategy: matrix: bus: ["axi", "ahb"] test: ["hello_world", "hello_world_dccm", "hello_world_iccm", "cmark", "cmark_dccm", "cmark_iccm", "dhry", "ecc", "csr_misa", "csr_access", "csr_mstatus", "csr_mseccfg", "modesw", "insns", "irq", "perf_counters", "pmp", "pmp_random", "write_unaligned", "icache", "bitmanip", "read_after_read"] coverage: ["all"] priv: ["0", "1"] tb_extra_args: ["--test-halt"] # hello_world_iccm will also have --test-lsu-clk-ratio exclude: # These tests require user mode - priv: "0" test: "csr_mseccfg" - priv: "0" test: "csr_access" - priv: "0" test: "csr_mstatus" - priv: "0" test: "modesw" - priv: "0" test: "insns" - priv: "0" test: "perf_counters" # end tests which require user mode env: DEBIAN_FRONTEND: "noninteractive" CCACHE_DIR: "/opt/regression/.cache/" steps: - name: Install utils run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null echo "debconf debconf/frontend select Noninteractive" | sudo debconf-set-selections sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ git python3 python3-pip build-essential ninja-build ccache \ gcc-riscv64-unknown-elf pip3 install meson --break-system-packages - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt echo "PATH=$PATH" >> $GITHUB_ENV - name: Setup environment run: | echo "/opt/verilator/bin" >> $GITHUB_PATH RV_ROOT=`pwd` echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV PYTHONUNBUFFERED=1 echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV TEST_PATH=$RV_ROOT/test_results echo "TEST_PATH=$TEST_PATH" >> $GITHUB_ENV echo "FULL_NAME=${{ matrix.bus }}-${{ matrix.test }}-${{ matrix.priv == 0 && 'm' || 'mu' }}-waypack${WAYPACK}-num-ways${NUM_WAYS}" >> $GITHUB_ENV - name: Run tests run: | export PATH=/opt/verilator/bin:$PATH export RV_ROOT=`pwd` export TB_EXTRA_ARGS="${{ matrix.tb_extra_args }}" # Use hello_world_iccm for testing '--test-lsu-clk-ratio' if [ ${{ matrix.test }} = hello_world_iccm ]; then export TB_EXTRA_ARGS="$TB_EXTRA_ARGS --test-lsu-clk-ratio" fi .github/scripts/run_regression_test.sh $TEST_PATH ${{ matrix.bus }} ${{ matrix.test}} ${{ matrix.coverage }} ${{ matrix.priv }} $WAYPACK - name: Prepare coverage data run: | source .venv/bin/activate mkdir -p results .github/scripts/convert_dat.sh ${TEST_PATH}/coverage.dat results/coverage_${FULL_NAME} - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: regression_tests_coverage_data_cache_waypack_${{ env.FULL_NAME }}_${{ matrix.coverage }} path: results/*.info custom-regression-tests: name: Custom regression tests runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 strategy: matrix: bus: ["axi", "ahb"] test: ["hello_world", "hello_world_dccm", "hello_world_iccm", "cmark", "cmark_dccm", "cmark_iccm", "dhry", "ecc", "csr_misa", "csr_access", "csr_mstatus", "csr_mseccfg", "modesw", "insns", "irq", "perf_counters", "pmp", "write_unaligned", "icache", "bitmanip", "read_after_read"] priv: ["0", "1"] ecc: ["0", "1"] exclude: # These tests require user mode - priv: "0" test: "csr_mseccfg" - priv: "0" test: "csr_access" - priv: "0" test: "csr_mstatus" - priv: "0" test: "modesw" - priv: "0" test: "insns" - priv: "0" test: "perf_counters" # end tests which require user mode # These tests require AHB bus - bus: "axi" test: "read_after_read" # end tests which require AHB bus env: GHA_EXTERNAL_DISK: additional-tools GHA_SA: gh-sa-veer-uploader steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Run tests run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_custom_regression_tests_waypack TEST: ${{ matrix.test }} BUS: ${{ matrix.bus }} PRIV: ${{ matrix.priv }} ECC: ${{ matrix.ecc }} ================================================ FILE: .github/workflows/test-regression-dcls.yml ================================================ name: Regression tests DCLS on: workflow_call: defaults: run: shell: bash jobs: regression-tests: name: Regression tests runs-on: ubuntu-latest container: ghcr.io/antmicro/cores-veer-el2:20250411084921 strategy: matrix: bus: ["axi", "ahb"] # run some subset of regression tests on DCLS configutation test: ["hello_world", "hello_world_dccm", "dhry", "ecc", "csr_misa", "csr_access", "csr_mstatus", "csr_mseccfg", "perf_counters", "icache", "bitmanip"] coverage: ["branch"] priv: ["0", "1"] tb_extra_args: ["--test-halt"] exclude: # These tests require user mode - priv: "0" test: "csr_mseccfg" - priv: "0" test: "csr_access" - priv: "0" test: "csr_mstatus" - priv: "0" test: "modesw" - priv: "0" test: "insns" - priv: "0" test: "perf_counters" # end tests which require user mode include: # Use hello_world_iccm for testing '--test-lsu-clk-ratio' - test: "hello_world_iccm" bus: "axi" coverage: "branch" priv: "0" tb_extra_args: "--test-halt --test-lsu-clk-ratio" env: DEBIAN_FRONTEND: "noninteractive" CCACHE_DIR: "/opt/regression/.cache/" DCLS_ENABLE: "1" steps: - name: Install utils run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null echo "debconf debconf/frontend select Noninteractive" | sudo debconf-set-selections sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ git python3 python3-pip build-essential ninja-build ccache \ gcc-riscv64-unknown-elf pip3 install meson --break-system-packages - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt echo "PATH=$PATH" >> $GITHUB_ENV - name: Setup environment run: | echo "/opt/verilator/bin" >> $GITHUB_PATH RV_ROOT=`pwd` echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV PYTHONUNBUFFERED=1 echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV TEST_PATH=$RV_ROOT/test_results echo "TEST_PATH=$TEST_PATH" >> $GITHUB_ENV - name: Run tests run: | export PATH=/opt/verilator/bin:$PATH export RV_ROOT=`pwd` export TB_EXTRA_ARGS="${{ matrix.tb_extra_args }}" .github/scripts/run_regression_test.sh $TEST_PATH ${{ matrix.bus }} ${{ matrix.test}} ${{ matrix.coverage }} ${{ matrix.priv }} 0 custom-regression-tests: name: Custom regression tests runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 strategy: matrix: bus: ["axi", "ahb"] # run some subset of regression tests on DCLS configutation test: ["hello_world", "hello_world_dccm", "dhry", "ecc", "csr_misa", "csr_access", "csr_mstatus", "csr_mseccfg", "perf_counters", "icache", "bitmanip"] priv: ["0", "1"] exclude: # These tests require user mode - priv: "0" test: "csr_mseccfg" - priv: "0" test: "csr_access" - priv: "0" test: "csr_mstatus" - priv: "0" test: "modesw" - priv: "0" test: "insns" - priv: "0" test: "perf_counters" # end tests which require user mode env: GHA_EXTERNAL_DISK: additional-tools GHA_SA: gh-sa-veer-uploader steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Run tests run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_dcls_regression DCLS_ENABLE: "1" TEST: ${{ matrix.test }} BUS: ${{ matrix.bus }} PRIV: ${{ matrix.priv }} ================================================ FILE: .github/workflows/test-regression-exceptions.yml ================================================ name: Regression exceptions tests on: workflow_call: defaults: run: shell: bash jobs: regression-tests: name: Regression exceptions tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 strategy: matrix: bus: ["axi"] test: ["machine_external_ints", "dbus_store_error", "lsu_trigger_hit", "machine_external_vec_ints", "dside_pic_access_error", "iside_fetch_precise_bus_error", "dside_access_region_prediction_error", "cmark", "iside_core_local_unmapped_address_error", "dside_access_across_region_boundary", "nmi_pin_assertion", "dside_size_misaligned_access_to_non_idempotent_address", "dside_core_local_access_unmapped_address_error", "dbus_nonblocking_load_error", "internal_timer_ints", "ebreak_ecall", "illegal_instruction", "clk_override", "core_pause"] coverage: ["all"] cache_waypack: ["0", "1"] priv: ["0"] env: DEBIAN_FRONTEND: "noninteractive" CCACHE_DIR: "/opt/regression/.cache/" steps: - name: Install utils run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null echo "debconf debconf/frontend select Noninteractive" | sudo debconf-set-selections sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ git python3 python3-pip build-essential ninja-build ccache \ gcc-riscv64-unknown-elf pip3 install meson --break-system-packages - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt echo "PATH=$PATH" >> $GITHUB_ENV - name: Setup environment run: | echo "/opt/verilator/bin" >> $GITHUB_PATH RV_ROOT=`pwd` echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV PYTHONUNBUFFERED=1 echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV TEST_PATH=$RV_ROOT/test_results echo "TEST_PATH=$TEST_PATH" >> $GITHUB_ENV echo "FULL_NAME=${{ matrix.bus }}-exceptions-${{ matrix.test }}-waypack${{ matrix.cache_waypack }}" >> $GITHUB_ENV - name: Run tests run: | export PATH=/opt/verilator/bin:$PATH export RV_ROOT=`pwd` .github/scripts/run_regression_test.sh $TEST_PATH ${{ matrix.bus }} ${{ matrix.test}} ${{ matrix.coverage }} ${{ matrix.priv }} ${{ matrix.cache_waypack }} - name: Prepare coverage data run: | source .venv/bin/activate mkdir -p results .github/scripts/convert_dat.sh ${TEST_PATH}/coverage.dat \ results/coverage_${FULL_NAME} - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: regression_tests_coverage_data-${{ env.FULL_NAME }}_${{ matrix.coverage }} path: results/*.info custom-regression-exceptions-tests: name: Custom regression exceptions tests runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 env: GHA_EXTERNAL_DISK: additional-tools GHA_SA: gh-sa-veer-uploader steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Run tests run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_custom_regression_exceptions_tests ================================================ FILE: .github/workflows/test-renode.yml ================================================ name: Renode tests on: workflow_call: jobs: tests: runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 strategy: fail-fast: false env: DEBIAN_FRONTEND: "noninteractive" steps: - name: Clone repository uses: actions/checkout@v4 with: submodules: recursive - name: Install dependencies run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null echo "debconf debconf/frontend select Noninteractive" | sudo debconf-set-selections sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ git python3 python3-dev python3-pip build-essential ninja-build ccache \ gcc-riscv64-unknown-elf pip3 install meson --break-system-packages - name: Build tests run: | export RV_ROOT=`pwd` cd ./tools/renode ./build-all-tests.sh - name: Run tests run: | cd ./tools/renode pip3 install -r /opt/renode/tests/requirements.txt --break-system-packages /opt/renode/renode-test veer.robot - name: Upload artifacts if: always() uses: actions/upload-artifact@v4 with: name: renode_results path: | tools/renode/log.html tools/renode/report.html tools/renode/robot_output.xml ================================================ FILE: .github/workflows/test-riscof.yml ================================================ name: RISCOF tests on: workflow_call: defaults: run: shell: bash jobs: tests: name: Run RISCOF tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 strategy: fail-fast: false matrix: coverage: ["all"] env: DEBIAN_FRONTEND: "noninteractive" CCACHE_DIR: "/opt/riscof/.cache/" steps: - name: Install utils run: | sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ git ccache python3-minimal python3-pip device-tree-compiler \ build-essential ninja-build # ghcr.io/antmicro/cores-veer-el2:20250411084921 is ubuntu-22.04.5 which has a riscv toolchain # without the support for the Zicsr extension - name: Install cross-compiler run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ gcc-riscv64-unknown-elf riscv64-unknown-elf-gcc --version - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt echo "PATH=$PATH" >> $GITHUB_ENV - name: Install RISCOF run: | pip3 install git+https://github.com/riscv/riscof@a25e315 - name: Clone tests run: | mkdir -p riscof pushd riscof riscof --verbose info arch-test --clone popd - name: Skip tests run: | pushd riscof/riscv-arch-test/riscv-test-suite # This test accesses memory at address 0x0. # These accesses fail on Spike because it has a debug module in range [0x0; 0x1000). # VeeR doesn't have such restrictions, so they don't fail, which results in a test failure. rm -f rv32i_m/pmp/src/pmpm_cfg_A_tor_zero.S rm -f rv32i_m/pmp/src/pmpzca_misaligned_na4.S popd - name: Configure RISCOF run: | pushd riscof # Copy RISCOF configuration cp ../tools/riscof/config.ini ./ cp -r ../tools/riscof/spike ./ cp -r ../tools/riscof/veer ./ # Build the test list riscof testlist --config=config.ini --suite=riscv-arch-test/riscv-test-suite/ --env=riscv-arch-test/riscv-test-suite/env popd - name: Build VeeR model run: | export PATH=/opt/verilator/bin:$PATH export RV_ROOT=`pwd` pushd riscof VEER_OPTS="-set=user_mode=1 -set=smepmp=1" make -f $RV_ROOT/tools/Makefile verilator-build CONF_PARAMS="-set build_axi4 $VEER_OPTS" COVERAGE=${{ matrix.coverage }} popd - name: Run tests, collect coverage run: | export PATH=/opt/verilator/bin:/opt/spike/bin:$PATH pushd riscof riscof run --no-browser --config=config.ini --suite=riscv-arch-test/riscv-test-suite/ --env=riscv-arch-test/riscv-test-suite/env mkdir -p coverage verilator_coverage -write ./coverage/coverage.dat `find ./riscof_work/ -type f -name "coverage.dat"` popd - name: Prepare coverage data run: | export PATH=/opt/verilator/bin:$PATH .github/scripts/convert_dat.sh riscof/coverage/coverage.dat \ riscof/coverage/coverage_riscof-m - name: Prepare report run: | PYTEST_STYLE_SRC_DIR=$(pwd)/.github/scripts/pytest/ PYTEST_CSS=${PYTEST_STYLE_SRC_DIR}/css/styles.css pushd riscof/riscof_work bash ${PYTEST_STYLE_SRC_DIR}/style_pytest_report.sh ${PYTEST_STYLE_SRC_DIR} . report.html echo "/* Custom CSS */" >>style.css cat ${PYTEST_CSS} >>style.css popd - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: riscof_coverage_data_m_${{ matrix.coverage }} path: riscof/coverage/*.info - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: riscof-report_m_${{ matrix.coverage }} path: | riscof/riscof_work/report.html riscof/riscof_work/style.css riscof/riscof_work/assets riscof/riscof_work/script riscof/riscof_work/rv* !riscof/riscof_work/**/coverage.dat - name: Check failure run: | if res=$(grep -no riscof/riscof_work/report.html -e "&2 echo "Check the report in artifacts for details." >&2 exit 1 fi ================================================ FILE: .github/workflows/test-riscv-dv.yml ================================================ name: RISCV-DV tests on: workflow_call: defaults: run: shell: bash env: ITERATIONS: 3 SEED: 999 jobs: generate-config: name: Generate configs runs-on: ubuntu-24.04 outputs: test-types: ${{ steps.test-types.outputs.tests }} test-include-generate: ${{ steps.test-types.outputs.include-generate }} test-include-run: ${{ steps.test-types.outputs.include-run }} test-include-run-custom: ${{ steps.test-types.outputs.include-run-custom }} # The same exclude can be used in both `run-tests` and `run-custom-tests` jobs cause they # exclude all matrix entries with matching keys regardless of other keys so it doesn't matter # that matrix in `run-tests` has twice the entries from `run-tests-custom` due to `coverage`. test-exclude-run: ${{ steps.test-types.outputs.exclude-run }} hash: ${{ steps.hash.outputs.files-hash }} steps: - uses: actions/checkout@v4 with: submodules: recursive - id: test-types run: | python3 -m pip install pyyaml echo "tests=$(python3 .github/scripts/riscv_dv_parse_testlist.py tools/riscv-dv/testlist.yaml)" | tee -a $GITHUB_OUTPUT echo "include-generate=$(python3 .github/scripts/riscv_dv_matrix_include.py generate)" | tee -a $GITHUB_OUTPUT echo "include-run=$(python3 .github/scripts/riscv_dv_matrix_include.py run-tests)" | tee -a $GITHUB_OUTPUT echo "include-run-custom=$(python3 .github/scripts/riscv_dv_matrix_include.py run-custom-tests)" | tee -a $GITHUB_OUTPUT echo "exclude-run=[ \ {'iss': 'renode', 'test': 'riscv_bitmanip_full_test_veer'}, \ {'iss': 'renode', 'test': 'riscv_bitmanip_balanced_test_veer'}, \ {'iss': 'renode', 'test': 'riscv_illegal_instr_test'}, \ {'iss': 'renode', 'test': 'riscv_hint_instr_test'}, \ {'iss': 'renode', 'test': 'riscv_ebreak_test', 'priv': 'mu'}, \ {'iss': 'renode', 'test': 'riscv_ebreak_debug_mode_test', 'priv': 'mu'} \ ]" | tee -a $GITHUB_OUTPUT - id: hash run: | echo "files-hash=$(.github/scripts/get_code_hash.sh)" | tee -a $GITHUB_OUTPUT generate-code: name: Generate code for tests runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 needs: generate-config strategy: fail-fast: false matrix: test: ${{ fromJSON(needs.generate-config.outputs.test-types) }} version: [ uvm ] include: ${{ fromJSON(needs.generate-config.outputs.test-include-generate) }} env: GHA_EXTERNAL_DISK: additional-tools CACHE_HASH: ${{ needs.generate-config.outputs.hash }} steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Prepare Environment run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_prepare_env - name: Generate code if: matrix.version == 'uvm' run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_generate_code RISCV_DV_TEST: ${{ matrix.test }} RISCV_DV_ITER: ${{ env.ITERATIONS }} RISCV_DV_SEED: ${{ env.SEED }} - name: Generate code (pyflow) if: matrix.version == 'pyflow' run: | export RV_ROOT=`realpath .` pushd tools/riscv-dv make -j`nproc` \ RISCV_DV_TEST=${{ matrix.test }} \ RISCV_DV_ITER=$ITERATIONS \ RISCV_DV_SEED=$SEED \ generate popd - name: Pack artifacts if: always() uses: actions/upload-artifact@v4 with: name: riscv-dv_generated_code_${{ matrix.test }}_${{ matrix.version }} path: tools/riscv-dv/work/**/asm_test/*.S run-tests: name: Run RISC-V DV tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 needs: [ generate-config, generate-code ] strategy: fail-fast: false matrix: test: ${{ fromJSON(needs.generate-config.outputs.test-types) }} iss: - spike - renode coverage: ["all"] version: [ uvm ] priv: ["m", "mu"] include: ${{ fromJSON(needs.generate-config.outputs.test-include-run) }} exclude: ${{ fromJSON(needs.generate-config.outputs.test-exclude-run) }} env: DEBIAN_FRONTEND: "noninteractive" CCACHE_DIR: "/opt/riscv-dv/.cache/" CACHE_HASH: ${{ needs.generate-config.outputs.hash }} steps: - name: Install utils run: | sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ git ccache device-tree-compiler python3-minimal python3-pip \ libboost-all-dev # As of July 9th, 2024 `ubuntu:latest` comes with riscv64-unknown-elf-gcc # 10.0.2. We need a newer version for bitmanip extension support. - name: Install cross-compiler run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ gcc-riscv64-unknown-elf riscv64-unknown-elf-gcc --version - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt echo "PATH=$PATH" >> $GITHUB_ENV - name: Install Python deps run: | pip install -r third_party/riscv-dv/requirements.txt - name: Download Code Artifact uses: actions/download-artifact@v4 with: name: riscv-dv_generated_code_${{ matrix.test }}_${{ matrix.version }} path: tools/riscv-dv/work/ - name: Run test run: | ls tools/riscv-dv/work export FULL_NAME=riscv_dv-${{ matrix.test }}-${{ matrix.priv }}-${{ matrix.iss }}-${{ matrix.version }} export PATH=/opt/verilator/bin:$PATH export RV_ROOT=`realpath .` export RISCV_GCC=riscv64-unknown-elf-gcc export RISCV_OBJCOPY=riscv64-unknown-elf-objcopy export RISCV_NM=riscv64-unknown-elf-nm export SPIKE_PATH=/opt/spike/bin export RENODE_PATH=/opt/renode/renode echo "FULL_NAME=${FULL_NAME}" >> $GITHUB_ENV echo "RV_ROOT=${RV_ROOT}" >> ${GITHUB_ENV} echo "PATH=${PATH}" >> ${GITHUB_ENV} ${RISCV_GCC} --version pushd tools/riscv-dv make -j`nproc` \ RISCV_DV_TEST=${{ matrix.test }} \ RISCV_DV_ISS=${{ matrix.iss }} \ RISCV_DV_ITER=$ITERATIONS \ RISCV_DV_SEED=$SEED \ COVERAGE=${{ matrix.coverage }} \ RISCV_DV_PRIV=${{ matrix.priv }} \ run popd - name: Prepare coverage data run: | mkdir -p results for ((i=0; i> $GITHUB_ENV # To avoid compiling code and running ISS on CentOS, let's just get # compiled code and ISS logs from the artifacts of Verilator tests. - name: Download Code and ISS logs uses: actions/download-artifact@v4 with: name: artifacts-${{ env.FULL_NAME }}-all path: verilator-artifacts - name: Move Code and ISS logs to workdir run: | SRC_DIR=verilator-artifacts/test_${{ matrix.test }} TEST_DIR=tools/riscv-dv/work/test_${{ matrix.test }} mkdir -p $TEST_DIR/asm_test cp $SRC_DIR/asm_test/*.hex $TEST_DIR/asm_test/ cp -r $SRC_DIR/${{ matrix.iss }}_sim $TEST_DIR/ rm -rf verilator-artifacts - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Prepare Environment run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_prepare_env - name: Perform custom tests run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_custom_riscv_dv RISCV_DV_ITER: ${{ env.ITERATIONS }} RISCV_DV_TEST: ${{ matrix.test }} RISCV_DV_PRIV: ${{ matrix.priv }} RISCV_DV_ISS: ${{ matrix.iss }} VERSION: ${{ matrix.version }} ================================================ FILE: .github/workflows/test-uarch.yml ================================================ name: VeeR-EL2 Microarchitectural tests on: workflow_call: defaults: run: shell: bash jobs: lint: name: Lint microarchitectural tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 steps: - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Setup environment run: | RV_ROOT=`pwd` echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV PYTHONUNBUFFERED=1 echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV TEST_PATH=$RV_ROOT/verification/block echo "TEST_PATH=$TEST_PATH" >> $GITHUB_ENV python3 -m venv .venv source .venv/bin/activate python3 -m pip install nox - name: Lint run: | source .venv/bin/activate pushd ${TEST_PATH} nox -s test_lint popd tests: name: Microarchitectural tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 strategy: matrix: include: - test: "block/pic" artifact: "block_pic" - test: "block/pic_gw" artifact: "block_pic_gw" - test: "block/dma" artifact: "block_dma" - test: "block/ifu_compress" artifact: "block_ifu_compress" - test: "block/ifu_mem_ctl" artifact: "block_ifu_mem_ctl" - test: "block/dec_tl" artifact: "block_dec_tl" - test: "block/dec_ib" artifact: "block_dec_ib" - test: "block/exu_alu" artifact: "block_exu_alu" - test: "block/exu_mul" artifact: "block_exu_mul" - test: "block/exu_div" artifact: "block_exu_div" - test: "block/iccm" artifact: "block_iccm" - test: "block/dccm" artifact: "block_dccm" - test: "block/lib_axi4_to_ahb" artifact: "block_lib_axi4_to_ahb" - test: "block/lib_ahb_to_axi4" artifact: "block_lib_ahb_to_axi4" - test: "block/pmp" artifact: "block_pmp" - test: "block/pmp_random" artifact: "block_pmp_random" - test: "block/dec_pmp_ctl" artifact: "block_dec_pmp_ctl" - test: "block/dmi" artifact: "block_dmi" - test: "block/lsu_tl" artifact: "block_lsu_tl" - test: "block/dec_tlu_ctl" artifact: "block_dec_tlu_ctl" - test: "block/dec" artifact: "block_dec" - test: "block/dcls" artifact: "block_dcls" env: CCACHE_DIR: "/opt/verification/.cache/" DEBIAN_FRONTEND: "noninteractive" steps: - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install prerequisites run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null echo "debconf debconf/frontend select Noninteractive" | sudo debconf-set-selections sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ autoconf automake autotools-dev \ bc bison build-essential \ ccache curl \ flex \ gawk gcc-riscv64-unknown-elf git gperf \ help2man \ libexpat-dev libfl-dev libfl2 libgmp-dev \ libmpc-dev libmpfr-dev libpython3-all-dev libtool \ ninja-build \ patchutils python3 python3-dev python3-pip \ texinfo \ zip zlib1g zlib1g-dev \ libbit-vector-perl - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt python3 -m pip install meson nox - name: Setup environment run: | echo "/opt/verilator/bin" >> $GITHUB_PATH RV_ROOT=`pwd` echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV PYTHONUNBUFFERED=1 echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV TEST_TYPE=`echo ${{ matrix.test }} | cut -d'/' -f1` TEST_NAME=`echo ${{ matrix.test }} | cut -d'/' -f2` TEST_PATH=$RV_ROOT/verification/${TEST_TYPE} echo "TEST_TYPE=$TEST_TYPE" >> $GITHUB_ENV echo "TEST_NAME=$TEST_NAME" >> $GITHUB_ENV echo "TEST_PATH=$TEST_PATH" >> $GITHUB_ENV # Fix random generator seed echo "RANDOM_SEED=1377424946" >> $GITHUB_ENV - name: Run ${{ matrix.test }} run: | source .venv/bin/activate pushd ${TEST_PATH} nox -s ${TEST_NAME}_verify popd zip verification/${{ matrix.test }}/dump.vcd.zip verification/${{ matrix.test }}/dump.vcd - name: Prepare coverage data run: | shopt -s extglob export PATH=/opt/verilator/bin:$PATH source .venv/bin/activate mkdir -p results for FILE in ${TEST_PATH}/${TEST_NAME}/*.dat; do .github/scripts/convert_dat.sh "${FILE}" "results/$(basename "${FILE%_@(all|branch|toggle).dat}")" done # Prefix coverage results pushd results for OLD_NAME in *.info; do # e.g. coverage_uarch-dma-ecc_line.info instead of coverage_test_ecc_line.info NEW_NAME=${OLD_NAME/coverage_/coverage_uarch-${TEST_NAME}-} NEW_NAME=${NEW_NAME/test_/} echo "renaming '${OLD_NAME}' to '${NEW_NAME}'" mv ${OLD_NAME} ${NEW_NAME} done popd - name: Upload coverage data artifacts if: always() uses: actions/upload-artifact@v4 with: name: uarch_tests_coverage_data-${{ matrix.artifact }} path: ./results/*.info - name: Upload test logs if: always() uses: actions/upload-artifact@v4 with: name: uarch_tests_logs-${{ matrix.artifact }} path: | verification/${{ matrix.test }}/*.log verification/${{ matrix.test }}/*.vcd.zip custom_tests: name: Run custom Microarchitectural tests runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 strategy: matrix: test: - "block/pic" - "block/pic_gw" - "block/dma" - "block/ifu_compress" - "block/ifu_mem_ctl" - "block/dec_tl" - "block/dec_ib" - "block/exu_alu" - "block/exu_mul" - "block/exu_div" - "block/iccm" - "block/dccm" - "block/lib_axi4_to_ahb" - "block/lib_ahb_to_axi4" - "block/pmp" - "block/pmp_random" - "block/dec_pmp_ctl" - "block/dmi" - "block/lsu_tl" - "block/dec_tlu_ctl" - "block/dec" env: GHA_EXTERNAL_DISK: additional-tools GHA_SA: gh-sa-veer-uploader TEST: ${{ matrix.test }} steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Perform custom tests run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_custom_uarch TEST: ${{ matrix.test }} ================================================ FILE: .github/workflows/test-uvm.yml ================================================ name: VeeR-EL2 verification on: workflow_call: jobs: tests: name: UVM tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 env: CCACHE_DIR: "/opt/uvm/.cache/" DEBIAN_FRONTEND: "noninteractive" steps: - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install prerequisities run: | sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ git build-essential ccache - name: Setup environment run: | echo "/opt/verilator/bin" >> $GITHUB_PATH RV_ROOT=`pwd` echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV PYTHONUNBUFFERED=1 echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV - name: Build UVM testbench run: | make -C testbench/uvm/mem build -j$(nproc) - name: Run UVM testbench run: | make -C testbench/uvm/mem simulate | tee test.out - name: Upload test output if: always() uses: actions/upload-artifact@v4 with: name: uvm_test_output path: test.out ================================================ FILE: .github/workflows/test-verification.yml ================================================ name: VeeR-EL2 verification on: workflow_call: defaults: run: shell: bash jobs: tests: name: Verification tests runs-on: ubuntu-24.04 container: ghcr.io/antmicro/cores-veer-el2:20250411084921 strategy: matrix: bus: ["ahb", "axi"] test: ["test_pyuvm"] coverage: ["all"] env: DEBIAN_FRONTEND: "noninteractive" CCACHE_DIR: "/opt/regression/.cache/" FULL_NAME: "${{ matrix.bus }}-verification-${{ matrix.test }}" steps: - name: Setup repository uses: actions/checkout@v4 with: submodules: recursive - name: Install prerequisities run: | echo "deb http://archive.ubuntu.com/ubuntu/ noble main universe" | sudo tee -a /etc/apt/sources.list > /dev/null echo "debconf debconf/frontend select Noninteractive" | sudo debconf-set-selections sudo apt -qqy update && sudo apt -qqy --no-install-recommends install \ autoconf automake autotools-dev \ bc bison build-essential \ ccache curl \ flex \ gawk gcc-riscv64-unknown-elf git gperf \ help2man \ libexpat-dev libfl-dev libfl2 libgmp-dev \ libmpc-dev libmpfr-dev libpython3-all-dev libtool \ ninja-build \ patchutils python3 python3-dev python3-pip \ texinfo \ zlib1g zlib1g-dev \ libbit-vector-perl - name: Install coverage dependencies run: | python3 -m venv .venv source .venv/bin/activate pip install -r .github/scripts/requirements-coverage.txt - name: Setup environment run: | echo "/opt/verilator/bin" >> $GITHUB_PATH RV_ROOT=`pwd` echo "RV_ROOT=$RV_ROOT" >> $GITHUB_ENV PYTHONUNBUFFERED=1 echo "PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> $GITHUB_ENV TEST_PATH=$RV_ROOT/verification/top/${{ matrix.test }} echo "TEST_PATH=$TEST_PATH" >> $GITHUB_ENV echo "HTML_FILE=${FULL_NAME}_${{ matrix.coverage }}.html" >> $GITHUB_ENV - name: Run ${{ matrix.test }} run: | source .venv/bin/activate pip3 install meson pip3 install -r $RV_ROOT/verification/top/requirements.txt PYTEST_STYLE_SRC_DIR=$RV_ROOT/.github/scripts/pytest/ PYTEST_CSS=${PYTEST_STYLE_SRC_DIR}/css/styles.css if [ ${{ matrix.bus }} = axi ]; then CONF_PARAMS='-set build_axi4' else CONF_PARAMS='-set build_ahb_lite' fi pushd ${TEST_PATH} python3 -m pytest ${{ matrix.test }}.py -sv --coverage=${{ matrix.coverage }} --html=$HTML_FILE --md=$GITHUB_STEP_SUMMARY --css=$PYTEST_CSS --conf_params="$CONF_PARAMS" bash ${PYTEST_STYLE_SRC_DIR}/style_pytest_report.sh ${PYTEST_STYLE_SRC_DIR} ${TEST_PATH} ${HTML_FILE} popd - name: Prepare pytest-html data run: | source .venv/bin/activate pushd $RV_ROOT WEBPAGE_DIR=webpage_${FULL_NAME}_${{ matrix.coverage }} mkdir -p $WEBPAGE_DIR mv ${TEST_PATH}/$HTML_FILE $WEBPAGE_DIR mv ${TEST_PATH}/assets $WEBPAGE_DIR JS_SCRIPT_DIR=$RV_ROOT/.github/scripts/pytest/script mv $JS_SCRIPT_DIR $WEBPAGE_DIR popd - name: Prepare coverage data run: | source .venv/bin/activate export PATH=/opt/verilator/bin:$PATH mkdir -p results .github/scripts/convert_dat.sh ${TEST_PATH}/coverage.dat \ results/coverage_${FULL_NAME/test_/} - name: Upload pytest-html artifacts if: always() uses: actions/upload-artifact@v4 with: name: verification_dashboard_${{ env.FULL_NAME }}_${{ matrix.coverage }} path: webpage_* - name: Upload coverage artifacts if: always() uses: actions/upload-artifact@v4 with: name: verification_tests_coverage_data_${{ env.FULL_NAME }}_${{ matrix.coverage }} path: results/*.info custom-verification-tests: name: Custom verification tests runs-on: [ self-hosted, Linux, X64, gcp-custom-runners ] container: centos:8 strategy: matrix: bus: ["axi", "ahb"] test: ["test_pyuvm"] env: GHA_EXTERNAL_DISK: additional-tools GHA_SA: gh-sa-veer-uploader steps: - uses: actions/checkout@v4 with: submodules: recursive - name: Set secrets version run: echo "SECRETS_VERSION=`cat .github/scripts/secrets_version`" >> $GITHUB_ENV - name: Run tests run: _secret_combined_${{ env.SECRETS_VERSION }} env: SECRET_NAME: _secret_custom_verification_tests TEST: ${{ matrix.test }} BUS: ${{ matrix.bus }} ================================================ FILE: .github/workflows/verible-format.yml ================================================ name: Verible formatter on: pull_request_target: jobs: format-review: runs-on: ubuntu-24.04 permissions: checks: write contents: read pull-requests: write steps: - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} - uses: antmicro/verible-formatter-action@update-upload-action with: github_token: ${{ secrets.GITHUB_TOKEN }} reviewdog_reporter: 'local' fail_on_formatting_suggestions: ${{ github.event_name != 'pull_request_target' }} ================================================ FILE: .github/workflows/verible-lint.yml ================================================ name: Verible linter on: pull_request_target: jobs: lint-review: runs-on: ubuntu-24.04 permissions: checks: write contents: read pull-requests: write steps: - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} - uses: chipsalliance/verible-linter-action@main with: github_token: ${{ secrets.GITHUB_TOKEN }} reviewdog_reporter: 'local' extra_args: '--waiver_files=./violations.waiver' paths: | ./design ================================================ FILE: .gitignore ================================================ configs/snapshots work obj_dir *.vcd *.csv *.log *.exe *.swp *.sym verilator-build program.hex snapshots __pycache__ sim_build sim-build* venv results.xml verification/sim verilator-cocotb-build *.dat *.xml *.json tools/renode/renode_run tools/renode/build tools/renode/*.elf tools/renode/.venv docs/build ================================================ FILE: .gitmodules ================================================ [submodule "third-party/picolibc"] path = third_party/picolibc url = https://github.com/picolibc/picolibc [submodule "third_party/riscv-dv"] path = third_party/riscv-dv url = https://github.com/chipsalliance/riscv-dv [submodule "third_party/cocotb"] path = third_party/cocotb url = https://github.com/cocotb/cocotb ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ================================================ FILE: MAINTAINERS.md ================================================ # Maintainers * [Maciej Kurc](https://github.com/mkurc-ant) * [Tomasz Michalak](https://github.com/tmichalak) * [Karol Gugala](https://github.com/kgugala) ================================================ FILE: README.md ================================================ # VeeR EL2 RISC-V Core This repository contains the VeeR EL2 RISC-V Core design RTL. ## License By contributing to this project, you agree that your contribution is governed by [Apache-2.0](LICENSE). Files under the [tools](tools/) directory may be available under a different license. Please review individual files for details. ## Directory Structure ├── configs # Configurations Dir │   └── snapshots # Where generated configuration files are created ├── design # Design root dir │   ├── dbg # Debugger │   ├── dec # Decode, Registers and Exceptions │   ├── dmi # DMI block │   ├── exu # EXU (ALU/MUL/DIV) │   ├── ifu # Fetch & Branch Prediction │   ├── include │   ├── lib │   └── lsu # Load/Store ├── docs ├── tools # Scripts/Makefiles └── testbench # (Very) simple testbench    ├── asm # Example assembly files    ├── hex # Canned demo hex files    └── tests # Example tests ## Dependencies - Verilator **(4.106 or later)** must be installed on the system if running with Verilator - If adding/removing instructions, [`espresso`](https://github.com/chipsalliance/espresso/tree/master) must be installed (used by `tools/coredecode`). Remember to checkout on `3.x` branch. - RISCV tool chain (based on gcc version 8.3 or higher) must be installed so that it can be used to prepare RISCV binaries to run. - [**Verible**](https://github.com/chipsalliance/verible) is used for SystemVerilog linting and formatting. - **Python 3.10+** is required for verification, documentation, and linting. ### Python Environment Setup It is recommended to use a virtual environment (venv) or Conda to manage Python dependencies. #### Using `venv` ```bash # Create a virtual environment python3 -m venv .venv # Activate it source .venv/bin/activate # Install all project dependencies pip install -r requirements.txt ``` #### Using `Conda` ```bash # Create a conda environment conda create -n veer-el2 python=3.12 # Activate it conda activate veer-el2 # Install dependencies pip install -r requirements.txt ``` ## Quickstart guide 1. Clone the repository, clone submodules with `git submodule update --init --recursive` 1. Setup `RV_ROOT` to point to the path in your local filesystem 1. Determine your configuration (optional) 1. Run `make` with `tools/Makefile` ## Release Notes for this version Please see [release notes](release-notes.md) for changes and bug fixes in this version of VeeR. ### Configurations VeeR can be configured by running the `$RV_ROOT/configs/veer.config` script: `% $RV_ROOT/configs/veer.config -h` for detailed help options For example to build with a DCCM of size 64 Kb: `% $RV_ROOT/configs/veer.config -dccm_size=64` This will update the **default** snapshot in `./snapshots/default/` with parameters for a 64K DCCM. Add `-snapshot=dccm64`, for example, if you wish to name your build snapshot `dccm64` and refer to it during the build. There are 4 predefined target configurations: `default`, `default_ahb`, `typical_pd` and `high_perf` that can be selected via the `-target=name` option to `veer.config`. **Note:** that the `typical_pd` target is what we base our published PPA numbers. It does not include an ICCM. **Building an FPGA speed optimized model:** Use ``-fpga_optimize=1`` option to ``veer.config`` to build a model that removes clock gating logic from flop model so that the FPGA builds can run at higher speeds. **This is now the default option for targets other than ``typical_pd``.** **Building a Power optimized model (ASIC flows):** Use ``-fpga_optimize=0`` option to ``veer.config`` to build a model that **enables** clock gating logic into the flop model so that the ASIC flows get a better power footprint. **This is now the default option for target``typical_pd``.** This script derives the following consistent set of include files: ./snapshots/default ├── common_defines.vh # `defines for testbench or design ├── defines.h # #defines for C/assembly headers ├── el2_param.vh # Design parameters ├── el2_pdef.vh # Parameter structure ├── pd_defines.vh # `defines for physical design ├── perl_configs.pl # Perl %configs hash for scripting ├── pic_map_auto.h # PIC memory map based on configure size └── whisper.json # JSON file for veer-iss └── link.ld # default linker control file ### Building a model While in a work directory: 1. Set the `RV_ROOT` environment variable to the root of the VeeR directory structure. Example for bash shell: `export RV_ROOT=/path/to/veer` Example for csh or its derivatives: `setenv RV_ROOT /path/to/veer` 1. Create your specific configuration *(Skip if default is sufficient)* *(Name your snapshot to distinguish it from the default. Without an explicit name, it will update/override the __default__ snapshot)* For example if `mybuild` is the name for the snapshot: `$RV_ROOT/configs/veer.config [configuration options..] -snapshot=mybuild` Snapshots are placed in the `./snapshots` directory 1. Run a simple Hello World program (Verilator) ```shell make -f $RV_ROOT/tools/Makefile ``` This command will build a Verilator model of VeeR EL2 with the AXI bus, and execute a short sequence of instructions that writes out "HELLO WORLD" to the bus. The simulation produces output on the screen like: ``` VerilatorTB: Start of sim ------------------------- Hello World from VeeR EL2 ------------------------- TEST_PASSED Finished : minstret = 437, mcycle = 922 See "exec.log" for execution trace with register updates.. ``` The simulation generates the following files: * `console.log` contains what the cpu writes to the console address of 0xd0580000. * `exec.log` shows instruction trace with GPR updates. * `trace_port.csv` contains a log of the trace port. When `debug=1` is provided, a vcd file `sim.vcd` is created and can be browsed by gtkwave or similar waveform viewers. You can re-execute the simulation using: ```shell make -f $RV_ROOT/tools/Makefile verilator ``` The simulation run/build command has following generic form: ```shell make -f $RV_ROOT/tools/Makefile [] [debug=1] [snapshot=mybuild] [target=] [TEST=] [TEST_DIR=] ``` where: ``` - can be 'verilator' (by default) 'irun' - Cadence xrun, 'vcs' - Synopsys VCS, 'vlog' Mentor Questa 'riviera'- Aldec Riviera-PRO. if not provided, 'make' cleans work directory, builds verilator executable and runs a test. debug=1 - allows VCD generation for verilator and VCS and SHM waves for irun option. assert=1 - enables assertions in simulation runs (with simulators other than Verilator) - predefined CPU configurations 'default' ( by default), 'default_ahb', 'typical_pd', 'high_perf' TEST - allows to run a C (.c) or assembly (.s) test, hello_world is run by default TEST_DIR - alternative to test source directory testbench/asm or testbench/tests - run and build executable model of custom CPU configuration, remember to provide 'snapshot' argument for runs on custom configurations. CONF_PARAMS - allows to provide -set options to veer.conf script to alter predefined EL2 targets parameters ``` Example: ```shell make -f $RV_ROOT/tools/Makefile verilator TEST=cmark ``` will build and simulate the `testbench/asm/cmark.c` program with Verilator. If you want to compile a test only, you can run: ```shell make -f $RV_ROOT/tools/Makefile program.hex TEST= [TEST_DIR=/path/to/dir] ``` The Makefile uses the `snapshot//link.ld` file, generated by the `veer.conf` script by default to build the test executable. User can provide test specific linker file in form `.ld` to build the test executable, in the same directory with the test source. User also can create a test-specific Makefile in `.makefile`, containing building instructions how to create the `program.hex` file used by simulation. The private Makefile should be in the same directory as the test source. See examples in the `testbench/asm` directory. Another way to alter test building process is to use `.mki` file in test source directory. It may help to select multiple sources to compile and/or alter compilation swiches. See examples in the `testbench/tests/` directory *(the `program.hex` file is loaded to instruction and LSU bus memory slaves and optionally to DCCM/ICCM at the beginning of simulation)*. User can build the `program.hex` file by any other means and then run simulation with the following command: ```shell make -f $RV_ROOT/tools/Makefile ``` Note: You may need to delete the `program.hex` file from the work directory, when running a new test. The `$RV_ROOT/testbench/asm` directory contains the following tests ready to simulate: ``` hello_world - default test program to run, prints Hello World message to screen and console.log hello_world_dccm - the same as above, but takes the string from preloaded DCCM. hello_world_iccm - the same as hello_world, but loads the test code to ICCM via LSU to DMA bridge and then executes it from there. Runs on EL2 with AXI4 buses only. cmark - coremark benchmark running with code and data in external memories cmark_dccm - the same as above, running data and stack from DCCM (faster) cmark_iccm - the same as above with preloaded code to ICCM (slower, optimized for size to fit into default ICCM). dhry - Run dhrystone. (Scale by 1757 to get DMIPS/MHZ) ``` The `$RV_ROOT/testbench/hex` directory contains precompiled hex files of the tests, ready for simulation in case RISC-V SW tools are not installed. **Note**: The testbench has a simple synthesizable bridge that allows you to load the ICCM via load/store instructions. This is only supported for AXI4 builds. ================================================ FILE: cm.cfg ================================================ +tree tb_top.rvtop_wrapper.rvtop ////////////////////////////////// MAIN CORE ////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //////////////////////////////// rvrangecheck ///////////////////////////////// // 'start_addr' and 'region' are tied to module parameters -node tb_top.rvtop_wrapper.rvtop.veer*rangecheck.start_addr -node tb_top.rvtop_wrapper.rvtop.veer*rangecheck.region ////////////////////////////// el2_veer_wrapper /////////////////////////////// -node tb_top.rvtop_wrapper.rvtop.unused_dmi_hard_reset -node tb_top.rvtop_wrapper.rvtop.trace_rv_i_address_ip[0] /////////////////////////////////// el2_veer ////////////////////////////////// -node tb_top.rvtop_wrapper.rvtop.veer.trace_rv_i_address_ip[0] -node tb_top.rvtop_wrapper.rvtop.veer.trace_rv_trace_pkt.trace_rv_i_address_ip[0] -node tb_top.rvtop_wrapper.rvtop.veer.*hprot[3:1] // Tied to 3'001 /////////////////////////////////// el2_dbg /////////////////////////////////// // Tied to '0 -node tb_top.rvtop_wrapper.rvtop.veer.dbg.abstractcs_reg[31:13] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.abstractcs_reg[11] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.abstractcs_reg[7:4] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.dmcontrol_reg[29] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.dmcontrol_reg[27:2] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.dmstatus_reg[31:20] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.dmstatus_reg[15:14] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.dmstatus_reg[6:4] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.haltsum0_reg[31:1] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.sbcs_reg[31:30] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.sbcs_reg[28:23] -node tb_top.rvtop_wrapper.rvtop.veer.dbg.dmstatus_reg[7] // Tied to '1 -node tb_top.rvtop_wrapper.rvtop.veer.dbg.dmstatus_reg[3:0] // Tied to 4'h2 -node tb_top.rvtop_wrapper.rvtop.veer.dbg.abstractcs_reg[3:0] // Tied to 4'h2 -node tb_top.rvtop_wrapper.rvtop.veer.dbg.sbcs_reg[29] // Tied to '1 -node tb_top.rvtop_wrapper.rvtop.veer.dbg.sbcs_reg[11:5] // Tied to 7'h20 -node tb_top.rvtop_wrapper.rvtop.veer.dbg.sbcs_reg[4:0] // Tied to 5'b01111 /////////////////////////////////// el2_exu /////////////////////////////////// -node tb_top.rvtop_wrapper.rvtop.veer.exu.i_mul.crc32_poly_rev // Tied to 32'hEDB88320 -node tb_top.rvtop_wrapper.rvtop.veer.exu.i_mul.crc32c_poly_rev // Tied to 32'h82F63B78 ////////////////////////////////// rvjtag_tap ///////////////////////////////// -node tb_top.rvtop_wrapper.rvtop.dmi_wrapper.i_jtag_tap.abits // Tied to AWID[5:0] ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.dcsr[14] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.dcsr[9] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.dcsr[5:4] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.dcsr_ns[14] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.dcsr_ns[9] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.dcsr_ns[5:4] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.ifu_mscause[2] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mcgc[6] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mcgc_int[6] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mcgc_ns[6] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mcountinhibit[1] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mepc_rf[0] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mie_rf[31] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mie_rf[27:12] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mie_rf[10:8] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mie_rf[6:4] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mie_rf[2:0] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mip_rf[27:12] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mip_rf[10:8] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mip_rf[6:4] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mip_rf[2:0] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mstatus_rf[31:17] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mstatus_rf[15:12] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mstatus_rf[10:8] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mstatus_rf[6:4] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mstatus_rf[2:0] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mtdata1_tsel_out[26] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mtdata1_tsel_out[18:13] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mtdata1_tsel_out[10:8] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mtdata1_tsel_out[5:3] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.pmp.*pmpcfg_ff.din[6:5] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.pmp.*pmpcfg_ff.dout[6:5] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[30:29] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[22:21] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[14:13] -node tb_top.rvtop_wrapper.rvtop.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[6:5] //////////////////////////// el2_ifu_compress_ctl ///////////////////////////// // Tied to '0 -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.o[31] -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.o[29:21] -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.o[19:15] -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.o[11:7] -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.o[1:0] // Tied to 2'b11 -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.l1[1:0] // Tied to o[1:0] (2'b11) -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.l2[1:0] // Tied to l1[1:0] (2'b11) -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.l3[1:0] // Tied to l2[1:0] (2'b11) -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.l1[31] // Tied to o[31] ('0) -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.l1[29:25] // Tied to o[29:25] ('0) -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.rdpd[4:3] // Tied to 2'01 -node tb_top.rvtop_wrapper.rvtop.veer.ifu.aln.compress0.rs2pd[4:3] // Tied to 2'01 ////////////////////////////////// LOCKSTEP /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //////////////////////////////// rvrangecheck ///////////////////////////////// // 'start_addr' and 'region' are tied to module parameters -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core*rangecheck.start_addr -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core*rangecheck.region ////////////////////////////// el2_veer_lockstep ////////////////////////////// -node tb_top.rvtop_wrapper.rvtop.lockstep.trace_rv_i_address_ip[0] -node tb_top.rvtop_wrapper.rvtop.lockstep.*trace_rv_i_address_ip[0] /////////////////////////////////// el2_veer ////////////////////////////////// -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.trace_rv_i_address_ip[0] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.trace_rv_trace_pkt.trace_rv_i_address_ip[0] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.*hprot[3:1] // Tied to 3'001 /////////////////////////////////// el2_dbg /////////////////////////////////// // Tied to '0 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.abstractcs_reg[31:13] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.abstractcs_reg[11] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.abstractcs_reg[7:4] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.dmcontrol_reg[29] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.dmcontrol_reg[27:2] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[31:20] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[15:14] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[6:4] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.haltsum0_reg[31:1] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[31:30] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[28:23] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[7] // Tied to '1 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[3:0] // Tied to 4'h2 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.abstractcs_reg[3:0] // Tied to 4'h2 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[29] // Tied to '1 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[11:5] // Tied to 7'h20 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[4:0] // Tied to 5'b01111 /////////////////////////////////// el2_exu /////////////////////////////////// -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.exu.i_mul.crc32_poly_rev // Tied to 32'hEDB88320 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.exu.i_mul.crc32c_poly_rev // Tied to 32'h82F63B78 ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr[14] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr[9] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr[5:4] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr_ns[14] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr_ns[9] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr_ns[5:4] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.ifu_mscause[2] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mcgc[6] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mcgc_int[6] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mcgc_ns[6] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mcountinhibit[1] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mepc_rf[0] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[31] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[27:12] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[10:8] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[6:4] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[2:0] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mip_rf[27:12] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mip_rf[10:8] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mip_rf[6:4] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mip_rf[2:0] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[31:17] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[15:12] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[10:8] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[6:4] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[2:0] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[26] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[18:13] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[10:8] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[5:3] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.*pmpcfg_ff.din[6:5] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.*pmpcfg_ff.dout[6:5] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[30:29] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[22:21] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[14:13] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[6:5] //////////////////////////// el2_ifu_compress_ctl ///////////////////////////// // Tied to '0 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[31] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[29:21] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[19:15] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[11:7] -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[1:0] // Tied to 2'b11 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l1[1:0] // Tied to o[1:0] (2'b11) -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l2[1:0] // Tied to l1[1:0] (2'b11) -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l3[1:0] // Tied to l2[1:0] (2'b11) -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l1[31] // Tied to o[31] ('0) -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l1[29:25] // Tied to o[29:25] ('0) -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.rdpd[4:3] // Tied to 2'01 -node tb_top.rvtop_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.rs2pd[4:3] // Tied to 2'01 ================================================ FILE: configs/README.md ================================================ # VeeR EL2 RISC-V Core ## Configuration ### Contents Name | Description ---------------------- | ------------------------------ VeeR.config | Configuration script for VeeR-EL2 veer_config_gen.py | Python wrapper to run veer.config, used by VeeRVolf This script will generate a consistent set of `defines/#defines/parameters` needed for the design and testbench. A perl hash (*perl_configs.pl*) and a JSON format for VeeR-iss are also generated. This set of include files : ./snapshots/ ├── common_defines.vh # `defines for testbench ├── defines.h # #defines for C/assembly headers ├── el2_param.vh # Actual Design parameters ├── el2_pdef.vh # Parameter structure definition ├── pd_defines.vh # `defines for physical design ├── perl_configs.pl # Perl %configs hash for scripting ├── pic_map_auto.h # PIC memory map based on configure size ├── whisper.json # JSON file for veer-iss └── link.ld # Default linker file for tests While the defines may be modified by hand, it is recommended that this script be used to generate a consistent set. ### Targets There are 4 predefined target configurations: `default`, `default_ahb`, `typical_pd` and `high_perf` that can be selected via the `-target=name` option to veer.config. Target | Description ---------------------- | ------------------------------ default | Default configuration. AXI4 bus interface default_ahb | Default configuration, AHB-Lite bus interface typical_pd | No ICCM, AXI4 bus interface high_perf | Large BTB/BHT, AXI4 interface `veer.config` may be edited to add additional target configurations, or new configurations may be created via the command line `-set` or `-unset` options. **Run `$RV_ROOT/configs/veer.config -h` for options and settable parameters.** ================================================ FILE: configs/veer.config ================================================ #! /usr/bin/env perl use strict; # Do not turn this off or else use Data::Dumper; use Getopt::Long; use Bit::Vector; use lib "$ENV{RV_ROOT}/tools"; use JSON; my ($self) = $0 =~ m/.*\/(\w+)/o; my @argv_orig = @ARGV; # Master configuration file # # Configuration is perl hash # Output are define files for various flows # Verilog (`defines common to RTL/TB) # Software (#defines) # Whisper (JSON/#defines) # # Default values and valid ranges should be specified # Can be overridden via the cmd line (-set=name=value-string) # # Format of the hash is # name => VALUE | LIST | HASH # # Special name "inside" followed by list .. values must be one of provided list # Special name "derive" followed by equation to derive # # Dump verilog/assembly macros in upper case my $defines_case = "U"; # Include these macros in verilog (pattern matched) my @verilog_vars = qw (xlen config_key reset_vec tec_rv_icg numiregs nmi_vec target protection.* testbench.* dccm.* retstack core.* iccm.* btb.* bht.* icache.* pic.* regwidth memmap bus.* tech_specific_.* user_.*); # Include these macros in assembly (pattern matched) my @asm_vars = qw (xlen reset_vec nmi_vec target dccm.* iccm.* pic.* memmap testbench.* protection.* core.*); my @asm_overridable = qw (reset_vec nmi_vec serialio external_data) ; # Include these macros in PD (pattern matched) my @pd_vars = qw (physical retstack target btb.* bht.* dccm.* iccm.* icache.* pic.* bus.* reset_vec nmi_vec build_ahb_lite datawidth ); # Dump non-derived/settable vars/values for these vars in stdout : my @dvars = qw(retstack btb bht core dccm iccm icache pic protection memmap bus); # Prefix all macros with my $prefix = "RV_"; # No prefix if keyword has my $no_prefix = 'RV|TOP|tec_rv_icg|regwidth|clock_period|^datawidth|verilator|SDVT_AHB|tech_specific_.*|user_ec_rv_icg'; my $vlog_use__wh = 1; my %regions_used = (); # Cmd Line options#{{{ our %sets; our %unsets; my $help; my @sets = (); my @unsets = (); #Configurations may be changed via the -set option # # -set=name=value : Change the default config parameter value (lowercase)\n"; # -unset=name : Remove the default config parameter (lowercase)\n"; # : Do not prepend RV_ prefex to -set/-unset variables\n"; # : multiple -set/-unset options accepted\n\n"; # my $helpusage = " Main configuration database for VeeR This script documents, and generates the {`#} define/include files for verilog/assembly/backend flows It is run by vsim (with defaults) every time the file changes, or when -config_set=VAR=value options are passed to vsim This script can be run stand-alone by processes not running vsim User options: -target = {default, default_ahb, high_perf, typical_pd} use default settings for one of the targets -set=var=value set arbitrary variable(parameter) to a value -unset=var unset any definitions for var -snapshot=name name the configuration (only if no -target specified) Parameters that can be set by the end user: -set=user_mode = {0,1} enable, disable user mode support in the core -set=ret_stack_size = {2, 3, 4, ... 8} size of return stack -set=btb_enable = {0,1} BTB enabled -set=btb_fullya = {0,1} BTB Fully set-associative -set=btb_size = { 8, 16, 32, 64, 128, 256, 512 } size of branch target buffer -set=bht_size = {32, 64, 128, 256, 512, 1024, 2048} size of branch history buffer -set=div_bit = {1,2,3,4} number of bits to process each cycle -set=div_new = {0,1} new div algorithm -set=dccm_enable = {0,1} DCCM enabled -set=dccm_num_banks = {2, 4} DCCM number of banks -set=dccm_region = { 0x0, 0x1, ... 0xf } number of 256Mb memory region containig DCCM -set=dccm_offset = hexadecimal offset (in bytes) of DCCM witin dccm_region dccm address will be: 256M * dccm_region + dccm_offset\", and that must be aligned to the dccm size or the next larger power of 2 if size is not a power of 2 -set=dccm_size = { 4, 8, 16, 32, 48, 64, 128, 256, 512 } kB size of DCCM -set=dma_buf_depth = {2,4,5} DMA buffer depth -set=fast_interrupt_redirect = {0, 1} Fast interrupt redirect mechanism -set=iccm_enable = { 0, 1 } whether or not ICCM is enabled -set=icache_enable = { 0, 1 } whether or not icache is enabled -set=icache_waypack = { 0, 1 } whether or not icache packing is enabled -set=icache_ecc = { 0, 1 } whether or not icache has ecc - EXPENSIVE 30% sram growth default: icache_ecc==0 (parity) -set=icache_size = { 8, 16, 32, 64, 128, 256 } kB size of icache -set=icache_2banks = {0,1} Enable 2 banks for icache -set=icache_num_ways { 2,4} Number of ways in icache -set=icache_bypass_enable = {0,1} Enable Icache data bypass buffer -set=icache_num_bypass = {1..8} Number of entries in bypass buffer -set=icache_num_tag_bypass = {1..8} Number of entries in bypass buffer -set=icache_tag_bypass_enable = {0,1} Enable icache tag bypass buffer -set=iccm_region = { 0x0, 0x1, ... 0xf } number of 256Mb memory region containing ICCM -set=iccm_offset = hexadecimal offcet (in bytes) of ICCM within iccm_region iccm address will be: \"256M * iccm_region + iccm_offset\", and that must be aligned to the iccm size or the next larger power of 2 if size is not a power of 2 -set=iccm_size = { 4 , 8 , 16 , 32, 64, 128, 256, 512 } kB size of ICCM -set=iccm_num_banks = {2,4,8,16} Number of ICCM banks -set=iccm_ecc_width Width of ICCM ECC [bits] -set=lsu_stbuf_depth = {2,4,8 } LSU stbuf depth -set=lsu_num_nbload = {2,4,8 } LSU number of outstanding Non Blocking loads -set=load_to_use_plus1 = {0 1} Load to use latency (fast or +1cycle) -set=pic_2cycle = { 0, 1 } whether or not 2-cycle PIC is enabled (2 cycle pic may result in an overall smaller cycle time) -set=pic_region = { 0x0, 0x1, ... 0xf } number of 256Mb memory region containing PIC memory-mapped registers -set=pic_offset = hexadecial offset (in bytes) of PIC within pic_region pic address will be: \"256M * pic_region + pic_offset\", and that must be aligned to the pic size or the next larger power of 2 if size is not a power of 2 -set=pic_size = { 32, 64, 128, 256 } kB size of PIC -set=pic_total_int = { 1, 2, 3, ..., 255 } number of interrupt sources in PIC -set=dma_buf_depth = {2,4,5} DMA buffer depth -set=timer_legal_en = {0,1} Internal timers legal/enabled -set=bitmanip_zba = {0,1} Bit manipulation extension ZBa enabled/legal -set=bitmanip_zbb = {0,1} Bit manipulation extension ZBb enabled/legal -set=bitmanip_zbc = {0,1} Bit manipulation extension ZBc enabled/legal -set=bitmanip_zbe = {0,1} Bit manipulation extension ZBe enabled/legal -set=bitmanip_zbf = {0,1} Bit manipulation extension ZBf enabled/legal -set=bitmanip_zbp = {0,1} Bit manipulation extension ZBp enabled/legal -set=bitmanip_zbr = {0,1} Bit manipulation extension ZBr enabled/legal -set=bitmanip_zbs = {0,1} Bit manipulation extension ZBs enabled/legal -fpga_optimize = { 0, 1 } if 1, minimize clock-gating to facilitate FPGA builds -text_in_iccm = {0, 1} Don't add ICCM preload code in generated link.ld -set=pmp_entries = {0, 16, 64 } number of PMP entries -set=smepmp = {0, 1} Enable Smepmp PMP extension -set=lockstep_enable = {0, 1} Enable Dual Core Lockstep (DCLS) in the core -set=lockstep_regfile_enable = {0, 1} Enable observing register file in the DCLS -set=lockstep_delay = {2, 3, 4} Set delay value for the Dual Core Lockstep Additionally the following may be set for bus masters and slaves using the -set=var=value option: {inst|data}_access_enable[0-7] : default 0 {inst|data}_access_addr[0-7] : default 0x00000000 {inst|data}_access_mask[0-7] : default 0xffffffff "; my $user_mode; my $ret_stack_size; my $btb_size; my $bht_size; my $btb_fullya; my $btb_toffset_size; my $dccm_region; my $dccm_offset; my $dccm_size; my $iccm_enable; my $icache_enable; my $icache_waypack; my $icache_num_ways; my $icache_banks_way; my $icache_ln_sz; my $icache_bank_width; my $icache_ecc; my $iccm_region; my $iccm_offset; my $iccm_size; my $icache_size; my $pic_2cycle; my $pic_region; my $pic_offset; my $pic_size; my $pic_total_int; my $top_align_iccm = 0; my $target = "default"; my $snapshot ; my $build_path ; my $verbose; my $load_to_use_plus1; my $btb_enable; my $dccm_enable; my $icache_2banks; my $lsu_stbuf_depth; my $dma_buf_depth; my $lsu_num_nbload; my $dccm_num_banks; my $iccm_num_banks; my $iccm_ecc_width; my $verilator; my $icache_bypass_enable=1; my $icache_num_bypass=2; my $icache_num_bypass_width; my $icache_tag_bypass_enable=1; my $icache_tag_num_bypass=2; my $icache_tag_num_bypass_width; my $fast_interrupt_redirect = 1; # ON by default my $lsu_num_nbload=4; my $ahb = 0; my $axi = 1; my $openocd_test = 0; my $text_in_iccm = 0; my $lsu2dma = 0; my $pmp_entries=16; my $smepmp=0; my $lockstep_enable=0; my $lockstep_regfile_enable=0; my $lockstep_delay=3; $user_mode=0; $ret_stack_size=8; $btb_enable=1; $btb_fullya=0; $btb_toffset_size=12; $btb_size=512; $bht_size=512; $dccm_enable=1; $dccm_region="0xf"; $dccm_offset="0x40000"; #1*256*1024 $dccm_size=64; $dccm_num_banks=4; $iccm_enable=1; $iccm_region="0xe"; $top_align_iccm = 1; $iccm_offset="0xe000000"; #0x380*256*1024 $iccm_size=64; $iccm_num_banks=4; $iccm_ecc_width=7; $icache_enable=1; $icache_waypack=1; $icache_num_ways=2; $icache_banks_way=2; $icache_2banks=1; $icache_bank_width=8; $icache_ln_sz=64; $icache_ecc=1; $icache_size=16; $pic_2cycle=0; $pic_region="0xf"; $pic_offset="0xc0000"; # 3*256*1024 $pic_size=32; $pic_total_int=31; $load_to_use_plus1=0; $lsu_stbuf_depth=4; $dma_buf_depth=5; my $div_bit=4; # number of bits to process each cycle for div my $div_new=1; # old or new div algorithm my $fpga_optimize = 1; # Default bitmanip options my $bitmanip_zba = 1; my $bitmanip_zbb = 1; my $bitmanip_zbc = 1; my $bitmanip_zbe = 0; my $bitmanip_zbf = 0; my $bitmanip_zbp = 0; my $bitmanip_zbr = 0; my $bitmanip_zbs = 1; GetOptions( "help" => \$help, "target=s" => \$target, "snapshot=s" => \$snapshot, "verbose" => \$verbose, "load_to_use_plus1" => \$load_to_use_plus1, "ret_stack_size=s" => \$ret_stack_size, "btb_fullya" => \$btb_fullya, "btb_enable=s" => \$btb_enable, "btb_size=s" => \$btb_size, "bht_size=s" => \$bht_size, "dccm_enable=s" => \$dccm_enable, "dccm_region=s" => \$dccm_region, "dccm_offset=s" => \$dccm_offset, "dccm_size=s" => \$dccm_size, "dma_buf_depth" => \$dma_buf_depth, "iccm_enable=s" => \$iccm_enable, "icache_enable=s" => \$icache_enable, "icache_waypack=s" => \$icache_waypack, "icache_num_ways=s" => \$icache_num_ways, "icache_ln_sz=s" => \$icache_ln_sz, "icache_ecc=s" => \$icache_ecc, "icache_2banks=s" => \$icache_2banks, "iccm_region=s" => \$iccm_region, "iccm_offset=s" => \$iccm_offset, "iccm_size=s" => \$iccm_size, "lsu_stbuf_depth" => \$lsu_stbuf_depth, "lsu_num_nbload" => \$lsu_num_nbload, "pic_2cycle=s" => \$pic_2cycle, "pic_region=s" => \$pic_region, "pic_offset=s" => \$pic_offset, "pic_size=s" => \$pic_size, "pic_total_int=s" => \$pic_total_int, "icache_size=s" => \$icache_size, "set=s@" => \@sets, "unset=s@" => \@unsets, "fpga_optimize=s" => \$fpga_optimize, "text_in_iccm=s" => \$text_in_iccm, ) || die("$helpusage"); if ($help) { print "$helpusage\n"; exit; } if (!defined $snapshot ) { $snapshot = $target; } if (!defined $ENV{BUILD_PATH}) { $build_path = "$ENV{PWD}/snapshots/$snapshot" ; } else { $build_path = $ENV{BUILD_PATH}; } if (! -d "$build_path") { system ("mkdir -p $build_path"); } # Parameter file my $tdfile = "$build_path/el2_pdef.vh"; my $paramfile = "$build_path/el2_param.vh"; # Verilog defines file path my $vlogfile = "$build_path/common_defines.vh"; # Assembly defines file path my $asmfile = "$build_path/defines.h"; # PD defines file path my $pdfile = "$build_path/pd_defines.vh"; # Whisper config file path my $whisperfile = "$build_path/whisper.json"; # # Default linker file my $linkerfile = "$build_path/link.ld"; # Perl defines file path my $perlfile = "$build_path/perl_configs.pl"; my $opensource=0; # IDEA: is ghr at 5b the right size for el2 core if ($target eq "default") { } elsif ($target eq "lsu2dma_axi") { $lsu2dma = 1; $iccm_enable = 1; } elsif ($target eq "typical_pd") { print "$self: Using target \"typical_pd\"\n"; $fpga_optimize = 0; $ret_stack_size=2; $btb_size=32; $bht_size=128; $dccm_size=16; $dccm_num_banks=2; $iccm_enable=0; } elsif ($target eq "high_perf") { print "$self: Using target \"high_perf\"\n"; $btb_size=512; $bht_size=2048; } elsif ($target eq "default_ahb") { print "$self: Using target \"default_ahb\"\n"; $axi = 0; $ahb = 1; } else { die "$self: ERROR! Unsupported target \"$target\". Supported are 'default', 'default_ahb', 'typical_pd', 'high_perf', 'lsu2dma_axi\n" ; } # Configure triggers our @triggers = (#{{{ { "reset" => ["0x23e00000", "0x00000000", "0x00000000"], "mask" => ["0x081818c7", "0xffffffff", "0x00000000"], "poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"] }, { "reset" => ["0x23e00000", "0x00000000", "0x00000000"], "mask" => ["0x081810c7", "0xffffffff", "0x00000000"], "poke_mask" => ["0x081810c7", "0xffffffff", "0x00000000"] }, { "reset" => ["0x23e00000", "0x00000000", "0x00000000"], "mask" => ["0x081818c7", "0xffffffff", "0x00000000"], "poke_mask" => ["0x081818c7", "0xffffffff", "0x00000000"] }, { "reset" => ["0x23e00000", "0x00000000", "0x00000000"], "mask" => ["0x081810c7", "0xffffffff", "0x00000000"], "poke_mask" => ["0x081810c7", "0xffffffff", "0x00000000"] }, );#}}} # Configure CSRs our %csr = (#{{{ "mstatus" => { "reset" => "0x1800", # MPP bits hard wired to binrary 11. "mask" => "0x88", # Only mpie(7) & mie(3) bits writeable "exists" => "true", }, "mie" => { "reset" => "0x0", # Only external, timer, local, and software writeable "mask" => "0x70000888", "exists" => "true", }, "mip" => { "reset" => "0x0", # None of the bits are writeable using CSR instructions "mask" => "0x0", # Bits corresponding to error overflow, external, timer and stoftware # interrupts are modifiable "poke_mask" => "0x70000888", "exists" => "true", }, "mcountinhibit" => { "commnet" => "Performance counter inhibit. One bit per counter.", "reset" => "0x0", "mask" => "0x7d", "poke_mask" => "0x7d", "exists" => "true", }, "mcounteren" => { "exists" => "false", }, "mvendorid" => { "reset" => "0x45", "mask" => "0x0", "exists" => "true", }, "marchid" => { "reset" => "0x00000010", "mask" => "0x0", "exists" => "true", }, "mimpid" => { "reset" => "0x4", "mask" => "0x0", "exists" => "true", }, "misa" => { "reset" => "0x40001104", "mask" => "0x0", "exists" => "true", }, "tselect" => { "reset" => "0x0", "mask" => "0x3", # Four triggers "exists" => "true", }, "mhartid" => { "reset" => "0x0", "mask" => "0x0", "poke_mask" => "0xfffffff0", "exists" => "true", }, "dcsr" => { "reset" => "0x40000003", "mask" => "0x00008c04", "poke_mask" => "0x00008dcc", # cause field modifiable, nmip modifiable "exists" => "true", "debug" => "true", }, "cycle" => { "exists" => "false", }, "time" => { "exists" => "false", }, "instret" => { "exists" => "false", }, "mhpmcounter3" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmcounter4" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmcounter5" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmcounter6" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmcounter3h" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmcounter4h" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmcounter5h" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmcounter6h" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmevent3" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmevent4" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmevent5" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mhpmevent6" => { "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, # Remaining CSRs are non-standard. These are specific to VeeR "dicawics" => { "number" => "0x7c8", "reset" => "0x0", "mask" => "0x0130fffc", "exists" => "true", }, "dicad0" => { "number" => "0x7c9", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "dicad1" => { "number" => "0x7ca", "reset" => "0x0", "mask" => "0x3", "exists" => "true", }, "dicago" => { "number" => "0x7cb", "reset" => "0x0", "mask" => "0x0", "exists" => "true", }, "mitcnt0" => { "number" => "0x7d2", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mitbnd0" => { "number" => "0x7d3", "reset" => "0xffffffff", "mask" => "0xffffffff", "exists" => "true", }, "mitctl0" => { "number" => "0x7d4", "reset" => "0x1", "mask" => "0x00000007", "exists" => "true", }, "mitcnt1" => { "number" => "0x7d5", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mitbnd1" => { "number" => "0x7d6", "reset" => "0xffffffff", "mask" => "0xffffffff", "exists" => "true", }, "mitctl1" => { "number" => "0x7d7", "reset" => "0x1", "mask" => "0x0000000f", "exists" => "true", }, "mcpc" => { "comment" => "Core pause", "number" => "0x7c2", "reset" => "0x0", "mask" => "0x0", "exists" => "true", }, "mpmc" => { "number" => "0x7c6", "reset" => "0x2", "mask" => "0x2", "exists" => "true", }, "micect" => { "number" => "0x7f0", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "miccmect" => { "number" => "0x7f1", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mdccmect" => { "number" => "0x7f2", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", }, "mcgc" => { "number" => "0x7f8", "reset" => "0x200", "mask" => "0x000003ff", "poke_mask" => "0x000003ff", "exists" => "true", }, "mfdc" => { "number" => "0x7f9", "reset" => "0x00070000", "mask" => "0x00071fff", "exists" => "true", }, "mrac" => { "comment" => "Memory region io and cache control.", "number" => "0x7c0", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", "shared" => "true", }, "dmst" => { "comment" => "Memory synch trigger: Flush caches in debug mode.", "number" => "0x7c4", "reset" => "0x0", "mask" => "0x0", "exists" => "true", "debug" => "true", }, "dicawics" => { "comment" => "Cache diagnostics.", "number" => "0x7c8", "reset" => "0x0", "mask" => "0x0130fffc", "exists" => "true", "debug" => "true", }, "dicad0" => { "comment" => "Cache diagnostics.", "number" => "0x7c9", "reset" => "0x0", "mask" => "0xffffffff", "exists" => "true", "debug" => "true", }, "dicad1" => { "comment" => "Cache diagnostics.", "number" => "0x7ca", "reset" => "0x0", "mask" => "0x3", "exists" => "true", "debug" => "true", }, "dicago" => { "comment" => "Cache diagnostics.", "number" => "0x7cb", "reset" => "0x0", "mask" => "0x0", "exists" => "true", "debug" => "true", }, "meipt" => { "comment" => "External interrupt priority threshold.", "number" => "0xbc9", "reset" => "0x0", "mask" => "0xf", "exists" => "true", }, "meicpct" => { "comment" => "External claim id/priority capture.", "number" => "0xbca", "reset" => "0x0", "mask" => "0x0", "exists" => "true", }, "meicidpl" => { "comment" => "External interrupt claim id priority level.", "number" => "0xbcb", "reset" => "0x0", "mask" => "0xf", "exists" => "true", }, "meicurpl" => { "comment" => "External interrupt current priority level.", "number" => "0xbcc", "reset" => "0x0", "mask" => "0xf", "exists" => "true", }, "mfdht" => { "comment" => "Force Debug Halt Threshold", "number" => "0x7ce", "reset" => "0x0", "mask" => "0x0000003f", "exists" => "true", "shared" => "true", }, "mfdhs" => { "comment" => "Force Debug Halt Status", "number" => "0x7cf", "reset" => "0x0", "mask" => "0x00000003", "exists" => "true", }, "mscause" => { "number" => "0x7ff", "reset" => "0x0", "mask" => "0x0000000f", "exists" => "true", }, );#}}} # These are the peformance counters events implemented for el2s. An # event number from outside this list will be replaced by zero if # written to an MHPMEVENT CSR. my @perf_events = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 54, 55, 56, 512, 513, 514, 515, 516); # FIXME: PMP CSR handling #foreach my $i (0 .. 3) { # $csr{"pmpcfg$i"} = { "exists" => "false" }; #} #foreach my $i (0 .. 15) { # $csr{"pmpaddr$i"} = { "exists" => "false" }; #} # }}} # Main config hash, with default values # # Hash can be hierarchical with arbitrary levels # Hexadecimal values are prefixed with 0x # # For verilog, if bit width is expected, add to %width hash below # # NOTE: params/keys marked 'derived' are not settable via cmd line, unless they ALSO have the 'overridable' tag # our %config = (#{{{ "harts" => "1", "xlen" => "32", # Testbench, Do Not Override "numiregs" => "32", # Testbench, Do Not Override "regwidth" => "32", # Testbench, Do Not Override "reset_vec" => "0x80000000", # Testbench, Overridable "nmi_vec" => "0x11110000", # Testbench, Overridable "physical" => "1", "num_mmode_perf_regs" => "4", # Whisper only "max_mmode_perf_event" => "516", # Whisper only: performance counters event ids will be clamped to this "target" => $target, # Flow Infrastructure "config_key" => "derived", "tec_rv_icg" => "clockhdr", "retstack" => { "ret_stack_size" => "$ret_stack_size", # Design Parm, Overridable }, "btb" => { "btb_enable" => "$btb_enable", # Design Parm, Overridable "btb_fullya" => "$btb_fullya", # Design Parm, Overridable "btb_toffset_size" => "$btb_toffset_size", # Constant "btb_size" => "$btb_size", # Design Parm, Overridable "btb_index1_hi" => "derived", "btb_index1_lo" => "2", # Constant, Do Not Override "btb_index2_hi" => "derived", "btb_index2_lo" => "derived", "btb_index3_hi" => "derived", "btb_index3_lo" => "derived", "btb_addr_hi" => "derived", "btb_array_depth" => "derived", "btb_addr_lo" => "2", # Constant, Do Not Override "btb_btag_size" => "derived", "btb_btag_fold" => "derived", "btb_fold2_index_hash" => "derived", }, "bht" => { "bht_size" => "$bht_size", # Design Parm, Overridable "bht_addr_hi" => "derived", "bht_addr_lo" => "2", # Constant, Do Not Override "bht_array_depth" => "derived", "bht_ghr_size" => "derived", "bht_ghr_range" => "derived", "bht_hash_string" => "derived", "bht_ghr_hash_1" => "derived", }, "core" => { "user_mode" => "$user_mode", "div_bit" => "$div_bit", # Design Parm, Overridable "div_new" => "$div_new", # Design Parm, Overridable "lsu_stbuf_depth" => "$lsu_stbuf_depth", # Design Parm, Overridable "dma_buf_depth" => "$dma_buf_depth", # Design Parm, Overridable "lsu_num_nbload" => "$lsu_num_nbload", # Design Parm, Overridable "opensource" => "$opensource", # Flow Infrastructure "verilator" => "$verilator", # Flow Infrastructure "load_to_use_plus1" => "$load_to_use_plus1", # Design Parm, Overridable "iccm_icache" => 'derived', # Used by design "iccm_only" => 'derived', # Used by design "icache_only" => 'derived', # Used by design "no_iccm_no_icache" => 'derived', # Used by design "timer_legal_en" => '1', # Design Parm, Overridable "bitmanip_zba" => $bitmanip_zba, # Design Parm, Overridable "bitmanip_zbb" => $bitmanip_zbb, # Design Parm, Overridable "bitmanip_zbc" => $bitmanip_zbc, # Design Parm, Overridable "bitmanip_zbe" => $bitmanip_zbe, # Design Parm, Overridable "bitmanip_zbf" => $bitmanip_zbf, # Design Parm, Overridable "bitmanip_zbp" => $bitmanip_zbp, # Design Parm, Overridable "bitmanip_zbr" => $bitmanip_zbr, # Design Parm, Overridable "bitmanip_zbs" => $bitmanip_zbs, # Design Parm, Overridable "fast_interrupt_redirect" => "$fast_interrupt_redirect", # Design Parm, Overridable "lsu2dma" => $lsu2dma, # used by design/TB for LSU to DMA bridge "fpga_optimize" => $fpga_optimize # Design Parm, Overridable }, "dccm" => { "dccm_enable" => "$dccm_enable", # Design Parm, Overridable "dccm_region" => "$dccm_region", # Design Parm, Overridable "dccm_offset" => "$dccm_offset", # Design Parm, Overridable "dccm_size" => "$dccm_size", # Design Parm, Overridable "dccm_num_banks" => "$dccm_num_banks", # Design Parm, Overridable "dccm_sadr" => 'derived', "dccm_eadr" => 'derived', "dccm_bits" => 'derived', "dccm_bank_bits" => 'derived', "dccm_data_width" => 'derived', "dccm_fdata_width" => 'derived', "dccm_byte_width" => 'derived', "dccm_width_bits" => 'derived', "dccm_index_bits" => 'derived', "dccm_ecc_width" => 'derived', "lsu_sb_bits" => 'derived', "dccm_data_cell" => 'derived', "dccm_rows" => 'derived', "dccm_reserved" => 'derived', # Testbench use only : reserve dccm space for SW/stack - no random r/w }, "iccm" => { "iccm_enable" => "$iccm_enable", # Design Parm, Overridable "iccm_region" => "$iccm_region", # Design Parm, Overridable "iccm_offset" => "$iccm_offset", # Design Parm, Overridable "iccm_size" => "$iccm_size", # Design Parm, Overridable "iccm_num_banks" => "$iccm_num_banks", # Design Parm, Overridable "iccm_bank_bits" => 'derived', "iccm_index_bits" => 'derived', "iccm_rows" => 'derived', "iccm_data_cell" => 'derived', "iccm_sadr" => 'derived', "iccm_eadr" => 'derived', "iccm_reserved" => 'derived', # Testbench use only : reserve iccm space for SW/handlers - no random r/w "iccm_bank_hi" => 'derived', "iccm_ecc_width" => "$iccm_ecc_width", "iccm_bank_index_lo" => 'derived', }, "icache" => { "icache_enable" => "$icache_enable", # Design Parm, Overridable "icache_waypack" => "$icache_waypack", # Design Parm, Overridable "icache_num_ways" => "$icache_num_ways", # Design Parm, Overridable "icache_banks_way" => "2", # Design Parm, Constant "icache_bank_width" => "8", # Design Parm, Constant "icache_ln_sz" => "$icache_ln_sz", # Design Parm, Overridable "icache_size" => "$icache_size", # Design Parm, Overridable "icache_bypass_enable" => "$icache_bypass_enable", # Design Parm, Overridable "icache_num_bypass" => "$icache_num_bypass", # Design Parm, Overridable "icache_num_bypass_width" => 'derived', "icache_tag_bypass_enable" => "$icache_tag_bypass_enable", # Design Parm, Overridable "icache_tag_num_bypass" => "$icache_tag_num_bypass", # Design Parm, Overridable "icache_tag_num_bypass_width" => 'derived', "icache_bank_hi" => 'derived', "icache_bank_lo" => 'derived', "icache_data_cell" => 'derived', "icache_tag_cell" => 'derived', "icache_tag_depth" => 'derived', "icache_data_depth" => 'derived', "icache_num_lines" => 'derived', "icache_num_lines_bank" => 'derived', "icache_num_lines_way" => 'derived', "icache_data_depth" => 'derived', "icache_tag_lo" => 'derived', "icache_index_hi" => 'derived', "icache_data_index_lo" => 'derived', "icache_data_width" => 'derived', "icache_fdata_width" => 'derived', "icache_tag_index_lo" => 'derived', "icache_ecc" => "$icache_ecc", # Design Parm, Overridable "icache_2banks" => "$icache_2banks", # Design Parm, Overridable "icache_bank_bits" => "derived", "icache_status_bits" => "derived", "icache_num_beats" => "derived", "icache_beat_bits" => "derived", "icache_scnd_last" => "derived", "icache_beat_addr_hi" => "derived", }, "pic" => { "pic_2cycle" => "$pic_2cycle", # Design Parm, Overridable "pic_region" => "$pic_region", # Design Parm, Overridable "pic_offset" => "$pic_offset", # Design Parm, Overridable "pic_size" => "$pic_size", # Design Parm, Overridable "pic_base_addr" => 'derived', "pic_total_int_plus1" => 'derived', # pic_total_int + 1 "pic_total_int" => "$pic_total_int", # Design Parm, Overridable "pic_int_words" => 'derived', # number of 32 bit words for packed registers (Xmax) "pic_bits" => 'derived', # of bits needs to address the PICM "pic_meipl_offset" => '0x0000', # Testbench only: Offset of meipl relative to pic_base_addr "pic_meip_offset" => '0x1000', # Testbench only: Offset of meip relative to pic_base_addr "pic_meie_offset" => '0x2000', # Testbench only: Offset of meie relative to pic_base_addr "pic_mpiccfg_offset" => '0x3000', # Testbench only: Offset of mpiccfg relative to pic_base_addr "pic_meipt_offset" => '0x3004', # Testbench only: Offset of meipt relative to pic_base_addr -- deprecated "pic_meigwctrl_offset" => '0x4000', # Testbench only: gateway control regs relative to pic_base_addr "pic_meigwclr_offset" => '0x5000', # Testbench only: gateway clear regs relative to pic_base_addr "pic_meipl_mask" => '0xf', # Whisper only "pic_meip_mask" => '0x0', "pic_meie_mask" => '0x1', "pic_mpiccfg_mask" => '0x1', "pic_meipt_mask" => '0x0', "pic_meigwctrl_mask" => '0x3', "pic_meigwclr_mask" => '0x0', "pic_meipl_count" => 'derived', "pic_meip_count" => 'derived', "pic_meie_count" => 'derived', "pic_mpiccfg_count" => 1, "pic_meipt_count" => 'derived', "pic_meigwctrl_count" => 'derived', "pic_meigwclr_count" => 'derived', }, "testbench" => { # Testbench only "TOP" => "tb_top", "RV_TOP" => "`TOP.rvtop_wrapper.rvtop", "CPU_TOP" => "`RV_TOP.veer", "clock_period" => "100", "build_ahb_lite" => "$ahb", "build_axi4" => "$axi", "build_axi_native" => "1", "openocd_test" => "$openocd_test", "ext_datawidth" => "64", "ext_addrwidth" => "32", "sterr_rollback" => "0", "lderr_rollback" => "1", "SDVT_AHB" => "$ahb", }, "protection" => { # Design parms, Overridable - static MPU "pmp_entries" => "$pmp_entries", "smepmp" => "$smepmp", "lockstep_enable" => "$lockstep_enable", "lockstep_regfile_enable" => "$lockstep_regfile_enable", "lockstep_delay" => "$lockstep_delay", "inst_access_enable0" => "0x0", "inst_access_addr0" => "0x00000000", "inst_access_mask0" => "0xffffffff", "inst_access_enable1" => "0x0", "inst_access_addr1" => "0x00000000", "inst_access_mask1" => "0xffffffff", "inst_access_enable2" => "0x0", "inst_access_addr2" => "0x00000000", "inst_access_mask2" => "0xffffffff", "inst_access_enable3" => "0x0", "inst_access_addr3" => "0x00000000", "inst_access_mask3" => "0xffffffff", "inst_access_enable4" => "0x0", "inst_access_addr4" => "0x00000000", "inst_access_mask4" => "0xffffffff", "inst_access_enable5" => "0x0", "inst_access_addr5" => "0x00000000", "inst_access_mask5" => "0xffffffff", "inst_access_enable6" => "0x0", "inst_access_addr6" => "0x00000000", "inst_access_mask6" => "0xffffffff", "inst_access_enable7" => "0x0", "inst_access_addr7" => "0x00000000", "inst_access_mask7" => "0xffffffff", "data_access_enable0" => "0x0", "data_access_addr0" => "0x00000000", "data_access_mask0" => "0xffffffff", "data_access_enable1" => "0x0", "data_access_addr1" => "0x00000000", "data_access_mask1" => "0xffffffff", "data_access_enable2" => "0x0", "data_access_addr2" => "0x00000000", "data_access_mask2" => "0xffffffff", "data_access_enable3" => "0x0", "data_access_addr3" => "0x00000000", "data_access_mask3" => "0xffffffff", "data_access_enable4" => "0x0", "data_access_addr4" => "0x00000000", "data_access_mask4" => "0xffffffff", "data_access_enable5" => "0x0", "data_access_addr5" => "0x00000000", "data_access_mask5" => "0xffffffff", "data_access_enable6" => "0x0", "data_access_addr6" => "0x00000000", "data_access_mask6" => "0xffffffff", "data_access_enable7" => "0x0", "data_access_addr7" => "0x00000000", "data_access_mask7" => "0xffffffff", }, "memmap" => { # Testbench only "serialio" => 'derived, overridable', # Testbench only "external_data" => 'derived, overridable', # Testbench only "debug_sb_mem" => 'derived, overridable', # Testbench only "external_data_1" => 'derived, overridable', # Testbench only "external_mem_hole" => 'default disabled', # Testbench only # "consoleio" => 'derived', # Part of serial io. }, "bus" => { "lsu_bus_tag" => 'derived', "lsu_bus_id" => '1', "lsu_bus_prty" => '2', "dma_bus_tag" => '1', "dma_bus_id" => '1', "dma_bus_prty" => '2', "sb_bus_tag" => '1', "sb_bus_id" => '1', "sb_bus_prty" => '2', "ifu_bus_tag" => 'derived', "ifu_bus_id" => '1', "ifu_bus_prty" => '2', "bus_prty_default" => '3', }, "triggers" => \@triggers, # Whisper only "csr" => \%csr, # Whisper only "perf_events" => \@perf_events, # Whisper only "even_odd_trigger_chains" => "true", # Whisper only "tech_specific_ec_rv_icg" => '0', "user_ec_rv_icg" => 'user_clock_gate', ); # These parms are used in the Verilog and will be part of global parm structure # need to have this be width in binary # for now autosize to the data our %verilog_parms = ( "user_mode" => '1', "lsu2dma" => '1', "timer_legal_en" => '1', "bitmanip_zbb" => '1', "bitmanip_zbs" => '1', "bitmanip_zba" => '1', "bitmanip_zbc" => '1', "bitmanip_zbe" => '1', "bitmanip_zbf" => '1', "bitmanip_zbp" => '1', "bitmanip_zbr" => '1', "fast_interrupt_redirect" => '1', "pmp_entries" => '7', "smepmp" => '1', "lockstep_enable" => '1', "lockstep_regfile_enable" => '1', "lockstep_delay" => '3', "inst_access_enable0" => '1', "inst_access_addr0" => '32', "inst_access_mask0" => '32', "inst_access_enable1" => '1', "inst_access_addr1" => '32', "inst_access_mask1" => '32', "inst_access_enable2" => '1', "inst_access_addr2" => '32', "inst_access_mask2" => '32', "inst_access_enable3" => '1', "inst_access_addr3" => '32', "inst_access_mask3" => '32', "inst_access_enable4" => '1', "inst_access_addr4" => '32', "inst_access_mask4" => '32', "inst_access_enable5" => '1', "inst_access_addr5" => '32', "inst_access_mask5" => '32', "inst_access_enable6" => '1', "inst_access_addr6" => '32', "inst_access_mask6" => '32', "inst_access_enable7" => '1', "inst_access_addr7" => '32', "inst_access_mask7" => '32', "data_access_enable0" => '1', "data_access_addr0" => '32', "data_access_mask0" => '32', "data_access_enable1" => '1', "data_access_addr1" => '32', "data_access_mask1" => '32', "data_access_enable2" => '1', "data_access_addr2" => '32', "data_access_mask2" => '32', "data_access_enable3" => '1', "data_access_addr3" => '32', "data_access_mask3" => '32', "data_access_enable4" => '1', "data_access_addr4" => '32', "data_access_mask4" => '32', "data_access_enable5" => '1', "data_access_addr5" => '32', "data_access_mask5" => '32', "data_access_enable6" => '1', "data_access_addr6" => '32', "data_access_mask6" => '32', "data_access_enable7" => '1', "data_access_addr7" => '32', "data_access_mask7" => '32', "iccm_bits" => '5', "iccm_bank_hi" => '5', "iccm_bank_index_lo" => '5', "icache_bank_bits" => '3', "icache_status_bits" => '3', "icache_num_beats" => '4', "icache_beat_bits" => '4', "icache_scnd_last" => '4', "icache_beat_addr_hi" => '4', "icache_bypass_enable" => '1', "icache_num_bypass" => '4', "icache_num_bypass_width" => '4', "icache_tag_bypass_enable" => '1', "icache_tag_num_bypass" => '4', "icache_tag_num_bypass_width" => '4', "iccm_icache" => '1', "iccm_only" => '1', "icache_only" => '1', "no_iccm_no_icache" => '1', "build_axi4" => '1', "build_ahb_lite" => '1', "build_axi_native" => '1', "lsu_num_nbload_width" => '3', "lsu_num_nbload" => '5', "ret_stack_size" => '4', "btb_fullya" => '1', "btb_toffset_size" => '5', "btb_enable" => '1', "btb_size" => '10', "btb_index1_hi" => '5', "btb_index1_lo" => '5', "btb_index2_hi" => '5', "btb_index2_lo" => '5', "btb_index3_hi" => '5', "btb_index3_lo" => '5', "btb_addr_hi" => '5', "btb_array_depth" => '9', "btb_addr_lo" => '2', "btb_btag_size" => '5', "btb_btag_fold" => '1', "btb_fold2_index_hash" => '1', "bht_size" => '12', "bht_addr_hi" => '4', "bht_addr_lo" => '2', "bht_array_depth" => '11', "bht_ghr_size" => '4', "bht_ghr_hash_1" => '1', "div_bit" => '3', "div_new" => '1', "lsu_stbuf_depth" => '4', "dma_buf_depth" => '3', "load_to_use_plus1" => '1', "dccm_enable" => '1', "dccm_region" => '4', "dccm_size" => '10', "dccm_num_banks" => '5', "dccm_sadr" => '32', "dccm_bits" => '5', "dccm_bank_bits" => '3', "dccm_data_width" => '6', "dccm_fdata_width" => '6', "dccm_byte_width" => '3', "dccm_width_bits" => '2', "dccm_index_bits" => '4', "dccm_ecc_width" => '3', "lsu_sb_bits" => '5', "iccm_enable" => '1', "iccm_region" => '4', "iccm_size" => '10', "iccm_num_banks" => '5', "iccm_bank_bits" => '3', "iccm_index_bits" => '4', "iccm_sadr" => '32', "iccm_ecc_width" => '3', "icache_enable" => '1', "icache_waypack" => '1', "icache_num_ways" => '3', "icache_banks_way" => '3', "icache_bank_width" => '4', "icache_ln_sz" => '7', "icache_size" => '9', "icache_bank_hi" => '3', "icache_bank_lo" => '2', "icache_tag_depth" => '13', "icache_data_depth" => '14', "icache_tag_lo" => '5', "icache_index_hi" => '5', "icache_data_index_lo" => '3', "icache_data_width" => '7', "icache_fdata_width" => '7', "icache_tag_index_lo" => '3', "icache_ecc" => '1', "icache_2banks" => '1', "pic_2cycle" => '1', "pic_region" => '4', "pic_size" => '9', "pic_base_addr" => '32', "pic_total_int_plus1" => '9', "pic_total_int" => '8', "pic_int_words" => '4', "pic_bits" => '5', "lsu_bus_tag" => '4', "lsu_bus_id" => '1', "lsu_bus_prty" => '2', "dma_bus_tag" => '4', "dma_bus_id" => '5', "dma_bus_prty" => '2', "sb_bus_tag" => '4', "sb_bus_id" => '1', "sb_bus_prty" => '2', "ifu_bus_tag" => '4', "ifu_bus_id" => '1', "ifu_bus_prty" => '2', "bus_prty_default" => '2', ); # to make sure parameter math works properly add 4 to each key of %verilog_parms - was an issue in btb calculations my $key; foreach $key (sort keys %verilog_parms) { if ( $key ne "user_mode" && $key ne "smepmp" ) { $verilog_parms{$key} += 4; } } # need to figure out what to do here # for now none of these can be parameters # move deletes lower # Perform any overrides first before derived values # map_set_unset(); gen_define("","", \%config,"",[]); # perform final checks my $c; $c=$config{retstack}{ret_stack_size}; if (!($c >=2 && $c <=8)) { die("$helpusage\n\nFAIL: ret_stack_size == $c; ILLEGAL !!!\n\n"); } $c=$config{btb}{btb_size}; if (!($c==8||$c==16||$c==32||$c==64||$c==128||$c==256||$c==512)) { die("$helpusage\n\nFAIL: btb_size == $c; ILLEGAL !!!\n\n"); } $c=$config{btb}{btb_size}; if (($c==64||$c==128||$c==256||$c==512) && $config{btb}{btb_fullya}) { die("$helpusage\n\nFAIL: btb_size == $c; btb_fullya=1 ILLEGAL !!!\n\n"); } $c=$config{iccm}{iccm_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: iccm_region == $c ILLEGAL !!!\n\n"); } $c=$config{iccm}{iccm_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: iccm_offset == $c ILLEGAL !!!\n\n"); } $c=$config{iccm}{iccm_size}; if (!($c==2||$c==4||$c==8||$c==16||$c==32||$c==64||$c==128||$c==256||$c==512)) { die("$helpusage\n\nFAIL: iccm_size == $c ILLEGAL !!!\n\n"); } $c=$config{iccm}{iccm_num_banks}; if (!($c==2 || $c==4 || ($c==8 && $config{iccm}{iccm_size} != 2) || ($c==16 && $config{iccm}{iccm_size} > 4))) { die("$helpusage\n\nFAIL: iccm_num_banks == $c ILLEGAL !!!\n\n"); } $c=$config{iccm}{iccm_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: iccm_enable == $c ILLEGAL !!!\n\n"); } $c=$config{dccm}{dccm_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: dccm_region == $c ILLEGAL !!!\n\n"); } $c=$config{dccm}{dccm_num_banks}; if (!(($c==2 && $config{dccm}{dccm_size} != 48) || $c==4 || ($c==8 && $config{dccm}{dccm_size} != 48) || ($c==16 && $config{dccm}{dccm_size} != 4 && $config{dccm}{dccm_size} != 48))) { die("$helpusage\n\nFAIL: dccm_num_banks == $c ILLEGAL !!!\n\n"); } $c=$config{dccm}{dccm_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: dccm_offset == $c ILLEGAL !!!\n\n"); } $c=$config{dccm}{dccm_size}; if (!($c==4||$c==8||$c==16||$c==32||$c==48||$c==64||$c==128||$c==256||$c==512)) { die("$helpusage\n\nFAIL: dccm_size == $c ILLEGAL !!!\n\n"); } $c=$config{pic}{pic_2cycle}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: pic_2cycle == $c ILLEGAL !!!\n\n"); } $c=$config{pic}{pic_region}; if (!($c>=0 && $c<16)) { die("$helpusage\n\nFAIL: pic_region == $c ILLEGAL !!!\n\n"); } $c=$config{pic}{pic_offset}; if (!($c>=0 && $c<256*1024*1024 && ($c&0xfff)==0)) { die("$helpusage\n\nFAIL: pic_offset == $c ILLEGAL !!!\n\n"); } $c=$config{pic}{pic_size}; if (!($c==32 || $c==64 || $c==128 || $c==256)) { die("$helpusage\n\nFAIL: pic_size == $c ILLEGAL !!!\n\n"); } $c=$config{pic}{pic_total_int}; if ( $c<1 || $c>255) { die("$helpusage\n\nFAIL: pic_total_int == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_num_bypass}; if ($c<1 || $c>8) { die("$helpusage\n\nFAIL: icache_num_bypass == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_bypass_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_bypass_enable == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_tag_num_bypass}; if ($c<1 || $c>8) { die("$helpusage\n\nFAIL: icache_tag_num_bypass == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_tag_bypass_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_tag_bypass_enable == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_enable}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_enable == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_waypack}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: icache_waypack == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_num_ways}; if (!($c==2 || $c==4)) { die("$helpusage\n\nFAIL: icache_num_ways == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_ln_sz}; if (!($c==32 || $c==64)) { die("$helpusage\n\nFAIL: icache_ln_sz == $c ILLEGAL !!!\n\n"); } $c=$config{icache}{icache_size}; if (!($c==8 || $c==16 || $c==32 || $c==64 || $c==128 || $c==256)) { die("$helpusage\n\nFAIL: icache_size == $c ILLEGAL !!!\n\n"); } $c=$config{core}{div_bit}; if (!($c==1 || $c==2 || $c==3 || $c==4 )) { die("$helpusage\n\nFAIL: div_bit == $c ILLEGAL !!!\n\n"); } $c=$config{core}{div_new}; if (!($c==0 || $c==1)) { die("$helpusage\n\nFAIL: div_new == $c ILLEGAL !!!\n\n"); } $c=$config{core}{lsu_stbuf_depth}; if (!($c==2 || $c==4 || $c==8)) { die("$helpusage\n\nFAIL: lsu_stbuf_depth == $c ILLEGAL !!!\n\n"); } $c=$config{core}{dma_buf_depth}; if (!($c==2 || $c==4 || $c==5)) { die("$helpusage\n\nFAIL: dma_buf_depth == $c ILLEGAL !!!\n\n"); } $c=$config{core}{lsu_num_nbload}; if (!($c==2 || $c==4 || $c==8)) { die("$helpusage\n\nFAIL: lsu_num_nbload == $c ILLEGAL !!!\n\n"); } # force div_bit to be 1 for old div algorithm if ($config{core}{div_new}==0 && $config{core}{div_bit}!=1) { die("$helpusage\n\nFAIL: div_new=0 requires div_bit=1 ILLEGAL !!!\n\n"); } $c=$config{protection}{pmp_entries}; if (!($c==64 || $c==16 || $c==0)) { die("$helpusage\n\nFAIL: pmp_entries must be either 0, 16 or 64 !!!\n\n"); } $c=$config{protection}{lockstep_delay}; if ($config{protection}{lockstep_enable} && ($c<2 || $c>4)) { die("$helpusage\n\nFAIL: lockstep_delay must fit in range <2, 4> !!!\n\n"); } $c=$config{protection}{inst_access_addr0}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr0 lower 6b must be 0s $c !!!\n\n"); } $c=$config{protection}{inst_access_addr1}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr1 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{inst_access_addr2}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr2 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{inst_access_addr3}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr3 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{inst_access_addr4}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr4 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{inst_access_addr5}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr5 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{inst_access_addr6}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr6 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{inst_access_addr7}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: inst_access_addr7 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{inst_access_mask0}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask0 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask1}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask1 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask2}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask2 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask3}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask3 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask4}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask4 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask5}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask5 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask6}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask6 invalid !!!\n\n"); } $c=$config{protection}{inst_access_mask7}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: inst_access_mask7 invalid !!!\n\n"); } $c=$config{protection}{data_access_addr0}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr0 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{data_access_addr1}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr1 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{data_access_addr2}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr2 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{data_access_addr3}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr3 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{data_access_addr4}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr4 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{data_access_addr5}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr5 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{data_access_addr6}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr6 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{data_access_addr7}; if ((hex($c)&0x3f) != 0) { die("$helpusage\n\nFAIL: data_access_addr7 lower 6b must be 0s !!!\n\n"); } $c=$config{protection}{data_access_mask0}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask0 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask1}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask1 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask2}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask2 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask3}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask3 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask4}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask4 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask5}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask5 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask6}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask6 invalid !!!\n\n"); } $c=$config{protection}{data_access_mask7}; if ((hex($c)&0x3f) != 63 || invalid_mask($c)) { die("$helpusage\n\nFAIL: data_access_mask7 invalid !!!\n\n"); } if ((hex($config{protection}{inst_access_addr0}) & hex($config{protection}{inst_access_mask0}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr0 and inst_access_mask0 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr1}) & hex($config{protection}{inst_access_mask1}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr1 and inst_access_mask1 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr2}) & hex($config{protection}{inst_access_mask2}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr2 and inst_access_mask2 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr3}) & hex($config{protection}{inst_access_mask3}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr3 and inst_access_mask3 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr4}) & hex($config{protection}{inst_access_mask4}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr4 and inst_access_mask4 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr5}) & hex($config{protection}{inst_access_mask5}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr5 and inst_access_mask5 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr6}) & hex($config{protection}{inst_access_mask6}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr6 and inst_access_mask6 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{inst_access_addr7}) & hex($config{protection}{inst_access_mask7}))!=0) { die("$helpusage\n\nFAIL: inst_access_addr7 and inst_access_mask7 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr0}) & hex($config{protection}{data_access_mask0}))!=0) { die("$helpusage\n\nFAIL: data_access_addr0 and data_access_mask0 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr1}) & hex($config{protection}{data_access_mask1}))!=0) { die("$helpusage\n\nFAIL: data_access_addr1 and data_access_mask1 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr2}) & hex($config{protection}{data_access_mask2}))!=0) { die("$helpusage\n\nFAIL: data_access_addr2 and data_access_mask2 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr3}) & hex($config{protection}{data_access_mask3}))!=0) { die("$helpusage\n\nFAIL: data_access_addr3 and data_access_mask3 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr4}) & hex($config{protection}{data_access_mask4}))!=0) { die("$helpusage\n\nFAIL: data_access_addr4 and data_access_mask4 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr5}) & hex($config{protection}{data_access_mask5}))!=0) { die("$helpusage\n\nFAIL: data_access_addr5 and data_access_mask5 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr6}) & hex($config{protection}{data_access_mask6}))!=0) { die("$helpusage\n\nFAIL: data_access_addr6 and data_access_mask6 must be orthogonal!!!\n\n"); } if ((hex($config{protection}{data_access_addr7}) & hex($config{protection}{data_access_mask7}))!=0) { die("$helpusage\n\nFAIL: data_access_addr7 and data_access_mask7 must be orthogonal!!!\n\n"); } # Fill in derived configuration entries. if (($config{icache}{icache_enable}==0 || grep(/icache_enable/, @unsets)) && $config{iccm}{iccm_enable}==0) { $config{core}{no_iccm_no_icache}=1; } elsif (($config{icache}{icache_enable}==0 || grep(/icache_enable/, @unsets)) && $config{iccm}{iccm_enable}==1) { $config{core}{iccm_only}=1; } elsif ($config{icache}{icache_enable}==1 && $config{iccm}{iccm_enable}==0) { $config{core}{icache_only}=1; } elsif ($config{icache}{icache_enable}==1 && $config{iccm}{iccm_enable}==1) { $config{core}{iccm_icache}=1; } if (!$config{dccm}{dccm_enable}) { $config{core}{fast_interrupt_redirect} = 0; print "$self: Disabling fast_interrupt_redirect because DCCM not enabled\n"; } $config{btb}{btb_btag_fold} = 0; $config{btb}{btb_fold2_index_hash} = 0; $config{btb}{btb_btag_size} = 31; if($config{btb}{btb_size}==512){ $config{btb}{btb_index1_hi} = 9; $config{btb}{btb_index2_hi} = 17; $config{btb}{btb_index3_hi} = 25; $config{btb}{btb_array_depth}= 256; $config{btb}{btb_btag_size} = 5; } elsif($config{btb}{btb_size}==256){ $config{btb}{btb_index1_hi} = 8; $config{btb}{btb_index2_hi} = 15; $config{btb}{btb_index3_hi} = 22; $config{btb}{btb_array_depth}= 128; $config{btb}{btb_btag_size} = 6; } elsif($config{btb}{btb_size}==128){ $config{btb}{btb_index1_hi} = 7; $config{btb}{btb_index2_hi} = 13; $config{btb}{btb_index3_hi} = 19; $config{btb}{btb_array_depth}= 64; $config{btb}{btb_btag_size} = 7; } elsif($config{btb}{btb_size}==64){ $config{btb}{btb_index1_hi} = 6; $config{btb}{btb_index2_hi} = 11; $config{btb}{btb_index3_hi} = 16; $config{btb}{btb_array_depth}= 32; $config{btb}{btb_btag_size} = 8; } elsif($config{btb}{btb_size}==32){ $config{btb}{btb_index1_hi} = 5; $config{btb}{btb_index2_hi} = 9; $config{btb}{btb_index3_hi} = 13; $config{btb}{btb_array_depth}= 16; $config{btb}{btb_btag_size} = 9 unless $config{btb}{btb_fullya}; $config{btb}{btb_btag_fold} = 1; } elsif($config{btb}{btb_size}<32){ #verif issues require these even though they are not needed $config{btb}{btb_index1_hi} = 5; $config{btb}{btb_index2_hi} = 8; $config{btb}{btb_index3_hi} = 11; $config{btb}{btb_fullya} = 1; } $config{btb}{btb_index2_lo} = $config{btb}{btb_index1_hi}+1; $config{btb}{btb_index3_lo} = $config{btb}{btb_index2_hi}+1; $config{btb}{btb_addr_hi} = $config{btb}{btb_index1_hi}; if($config{bht}{bht_size}==2048){ $config{bht}{bht_ghr_size}= 10; $config{bht}{bht_ghr_range}= "9:0"; $config{bht}{bht_array_depth}= 1024; $config{bht}{bht_addr_hi}= 11; } elsif($config{bht}{bht_size}==1024){ $config{bht}{bht_ghr_size}= 9; $config{bht}{bht_ghr_range}= "8:0"; $config{bht}{bht_array_depth}= 512; $config{bht}{bht_addr_hi}= 10; } elsif($config{bht}{bht_size}==512){ $config{bht}{bht_ghr_size}= 8; $config{bht}{bht_ghr_range}= "7:0"; $config{bht}{bht_array_depth}= 256; $config{bht}{bht_addr_hi}= 9; } elsif($config{bht}{bht_size}==256){ $config{bht}{bht_ghr_size}= 7; $config{bht}{bht_ghr_range}= "6:0"; $config{bht}{bht_addr_hi} = 8; $config{bht}{bht_array_depth}= 128; } elsif($config{bht}{bht_size}==128){ $config{bht}{bht_ghr_size}= 6; $config{bht}{bht_ghr_range}= "5:0"; $config{bht}{bht_addr_hi} = 7; $config{bht}{bht_array_depth}= 64; } elsif($config{bht}{bht_size}==64){ $config{bht}{bht_ghr_size}= 5; $config{bht}{bht_ghr_range}= "4:0"; $config{bht}{bht_addr_hi} = 6; $config{bht}{bht_array_depth}= 32; } elsif($config{bht}{bht_size}==32){ $config{bht}{bht_ghr_size}= 4; $config{bht}{bht_ghr_range}= "3:0"; $config{bht}{bht_addr_hi} = 5; $config{bht}{bht_array_depth}= 16; } $config{bht}{bht_ghr_hash_1} = ($config{bht}{bht_ghr_size} > ($config{btb}{btb_index1_hi}-1)); $config{bht}{bht_hash_string} = &ghrhash($config{btb}{btb_index1_hi}, $config{bht}{bht_ghr_size}); # PIC derived $config{pic}{pic_base_addr} = (hex($config{pic}{pic_region})<<28) + (hex($config{pic}{pic_offset})); $config{pic}{pic_base_addr} = sprintf("0x%x", $config{pic}{pic_base_addr}); $config{pic}{pic_int_words} = int($config{pic}{pic_total_int}/32 +0.9); $config{pic}{pic_bits} = 10 + log2($config{pic}{pic_size}); $config{pic}{pic_total_int_plus1} = $config{pic}{pic_total_int} + 1; $config{pic}{pic_meipl_count} = $config{pic}{pic_total_int}; $config{pic}{pic_meip_count} = $config{pic}{pic_int_words}; $config{pic}{pic_meie_count} = $config{pic}{pic_total_int}; $config{pic}{pic_meipt_count} = $config{pic}{pic_total_int}; $config{pic}{pic_meigwctrl_count} = $config{pic}{pic_total_int}; $config{pic}{pic_meigwclr_count} = $config{pic}{pic_total_int}; $config{icache}{icache_num_bypass_width} = int(log2($config{icache}{icache_num_bypass})) + 1; $config{icache}{icache_tag_num_bypass_width} = int(log2($config{icache}{icache_tag_num_bypass})) + 1; $config{core}{lsu_num_nbload_width} = log2($config{core}{lsu_num_nbload}); $config{bus}{lsu_bus_tag} = log2($config{core}{lsu_num_nbload}) + 1; $config{bus}{ifu_bus_tag} = log2($config{icache}{icache_ln_sz}/8); $config{dccm}{dccm_sadr} = (hex($config{dccm}{dccm_region})<<28) + (hex($config{dccm}{dccm_offset})); $config{dccm}{dccm_sadr} = sprintf("0x%x", $config{dccm}{dccm_sadr}); $config{dccm}{dccm_eadr} = (hex($config{dccm}{dccm_region})<<28) + (hex($config{dccm}{dccm_offset})) + size($config{dccm}{dccm_size})-1; $config{dccm}{dccm_eadr} = sprintf("0x%x", $config{dccm}{dccm_eadr}); $config{dccm}{dccm_reserved} = sprintf("0x%x", ($config{dccm}{dccm_size}>=16)? 5120 : ($config{dccm}{dccm_size}*1024)/4); $config{dccm}{dccm_bits} = ($config{dccm}{dccm_size}==48 ) ? 16 : 10 + log2($config{dccm}{dccm_size}); $config{dccm}{dccm_bank_bits} = log2($config{dccm}{dccm_num_banks}); $config{dccm}{dccm_data_width} = 32; $config{dccm}{dccm_fdata_width} = $config{dccm}{dccm_data_width} + log2($config{dccm}{dccm_data_width}) + 2; $config{dccm}{dccm_byte_width} = $config{dccm}{dccm_data_width}/8; $config{dccm}{dccm_width_bits} = log2($config{dccm}{dccm_byte_width}); $config{dccm}{dccm_index_bits} = $config{dccm}{dccm_bits} - $config{dccm}{dccm_bank_bits} - $config{dccm}{dccm_width_bits}; $config{dccm}{dccm_ecc_width} = log2($config{dccm}{dccm_data_width}) + 2; $config{dccm}{lsu_sb_bits} = $config{dccm}{dccm_bits}; $config{dccm}{dccm_rows} = ($config{dccm}{dccm_size}==48 ) ? (2**($config{dccm}{dccm_index_bits}-1) + 2**$config{dccm}{dccm_index_bits})/2 : 2**$config{dccm}{dccm_index_bits}; $config{dccm}{dccm_data_cell} = "ram_$config{dccm}{dccm_rows}x39"; $config{icache}{icache_num_lines} = $config{icache}{icache_size}*1024/$config{icache}{icache_ln_sz}; $config{icache}{icache_num_lines_way} = $config{icache}{icache_num_lines}/$config{icache}{icache_num_ways}; $config{icache}{icache_num_lines_bank} = $config{icache}{icache_num_lines}/($config{icache}{icache_num_ways} * $config{icache}{icache_banks_way}); $config{icache}{icache_data_depth} = $config{icache}{icache_num_lines_bank} * $config{icache}{icache_ln_sz} /$config{icache}{icache_bank_width}; $config{icache}{icache_data_index_lo} = log2($config{icache}{icache_bank_width}) + log2($config{icache}{icache_banks_way}); $config{icache}{icache_index_hi} = $config{icache}{icache_data_index_lo} + log2($config{icache}{icache_data_depth}) -1; $config{icache}{icache_bank_hi} = $config{icache}{icache_data_index_lo} - 1; $config{icache}{icache_bank_lo} = log2($config{icache}{icache_bank_width}); $config{icache}{icache_tag_index_lo} = log2($config{icache}{icache_ln_sz}); $config{icache}{icache_tag_lo} = log2($config{icache}{icache_num_lines_way}) + $config{icache}{icache_tag_index_lo}; $config{icache}{icache_tag_depth} = $config{icache}{icache_num_lines}/$config{icache}{icache_num_ways}; $config{icache}{icache_data_width} = 8*$config{icache}{icache_bank_width}; $config{icache}{icache_bank_bits} = 1+$config{icache}{icache_bank_hi}-$config{icache}{icache_bank_lo}; $config{icache}{icache_status_bits} = $config{icache}{icache_num_ways}-1; $config{icache}{icache_num_beats} = ($config{icache}{icache_ln_sz}==64) ? 8 : 4; $config{icache}{icache_beat_bits} = ($config{icache}{icache_ln_sz}==64) ? 3 : 2; $config{icache}{icache_scnd_last} = ($config{icache}{icache_ln_sz}==64) ? 6 : 2; $config{icache}{icache_beat_addr_hi} = ($config{icache}{icache_ln_sz}==64) ? 5 : 4; if (($config{icache}{icache_ecc})) { $config{icache}{icache_fdata_width} = $config{icache}{icache_data_width} + 7; $config{icache}{icache_data_cell} = "ram_$config{icache}{icache_data_depth}x$config{icache}{icache_fdata_width}"; $config{icache}{icache_tag_cell} = ($config{icache}{icache_tag_depth} == 32) ? "ram_$config{icache}{icache_tag_depth}x26" : "ram_$config{icache}{icache_tag_depth}x25"; } else { $config{icache}{icache_fdata_width} = $config{icache}{icache_data_width} + 4; $config{icache}{icache_data_cell} = "ram_$config{icache}{icache_data_depth}x$config{icache}{icache_fdata_width}"; $config{icache}{icache_tag_cell} = "ram_$config{icache}{icache_tag_depth}x21"; } $config{pic}{pic_total_int_plus1} = $config{pic}{pic_total_int} + 1; # Defines with explicit values in the macro name $config{dccm}{"dccm_num_banks_$config{dccm}{dccm_num_banks}"} = ""; $config{dccm}{"dccm_size_$config{dccm}{dccm_size}"} = ""; # If ICCM offset not explicitly provided, align to TOP of the region if ($top_align_iccm && ($config{iccm}{iccm_offset} eq $iccm_offset) && ($config{iccm}{iccm_size} < 32)) { $config{iccm}{iccm_region} = "0xa"; print "$self: Setting default iccm region to region $config{iccm}{iccm_region}\n"; $config{iccm}{iccm_offset} = sprintf("0x%08x",256*1024*1024-size($config{iccm}{iccm_size})); print "$self: Aligning default iccm offset to top of region @ $config{iccm}{iccm_offset}\n"; } $config{iccm}{iccm_sadr} = (hex($config{iccm}{iccm_region})<<28) + (hex($config{iccm}{iccm_offset})); $config{iccm}{iccm_sadr} = sprintf("0x%08x", $config{iccm}{iccm_sadr}); $config{iccm}{iccm_eadr} = (hex($config{iccm}{iccm_region})<<28) + (hex($config{iccm}{iccm_offset})) + size($config{iccm}{iccm_size})-1; $config{iccm}{iccm_eadr} = sprintf("0x%08x", $config{iccm}{iccm_eadr}); $config{iccm}{iccm_reserved} = sprintf("0x%x", ($config{iccm}{iccm_size}>30)? 4096 : ($config{iccm}{iccm_size}*1024)/4); $config{iccm}{iccm_bits} = 10 + log2($config{iccm}{iccm_size}); $config{iccm}{iccm_bank_bits} = log2($config{iccm}{iccm_num_banks}); //-1; $config{iccm}{iccm_index_bits} = $config{iccm}{iccm_bits} - $config{iccm}{iccm_bank_bits} - 2; # always 4 bytes $config{iccm}{iccm_rows} = 2**$config{iccm}{iccm_index_bits}; $config{iccm}{iccm_data_cell} = "ram_$config{iccm}{iccm_rows}x39"; $config{iccm}{iccm_bank_hi} = 2+$config{iccm}{iccm_bank_bits}-1; $config{iccm}{iccm_bank_index_lo} = 1+$config{iccm}{iccm_bank_hi}; # Defines with explicit values in the macro name $config{iccm}{"iccm_num_banks_$config{iccm}{iccm_num_banks}"} = ""; $config{iccm}{"iccm_size_$config{iccm}{iccm_size}"} = ""; # Track used regions $regions_used{hex($config{iccm}{iccm_region})} = 1; $regions_used{hex($config{dccm}{dccm_region})} = 1; $regions_used{hex($config{pic}{pic_region})} = 1; $regions_used{hex($config{reset_vec})>>28} = 1; # Find an unused region for serial IO for (my $rgn = 15;$rgn >= 0; $rgn--) { if (($rgn != hex($config{iccm}{iccm_region})) && ($rgn != hex($config{dccm}{dccm_region})) && ($rgn != (hex($config{pic}{pic_region})))) { $config{memmap}{serialio} = ($rgn << 28) + (22<<18); $regions_used{$rgn} = 1; last; } } $config{memmap}{serialio} = sprintf("0x%08x", $config{memmap}{serialio}); # Find an unused region for external data for (my $rgn = 15;$rgn >= 0; $rgn--) { if (($rgn != hex($config{iccm}{iccm_region})) && ($rgn != hex($config{dccm}{dccm_region})) && ($rgn != (hex($config{memmap}{serialio})>>28)) && ($rgn != (hex($config{pic}{pic_region})))) { $config{memmap}{external_data} = ($rgn << 28) + (22<<18); $regions_used{$rgn} = 1; last; } } $config{memmap}{external_data} = sprintf("0x%08x", $config{memmap}{external_data}); # # Unused region for second data for (my $rgn = 15;$rgn >= 0; $rgn--) { if (($rgn != hex($config{iccm}{iccm_region})) && ($rgn != hex($config{dccm}{dccm_region})) && ($rgn != (hex($config{memmap}{serialio})>>28)) && ($rgn != (hex($config{memmap}{external_data})>>28)) && ($rgn != (hex($config{pic}{pic_region})))) { $config{memmap}{external_data_1} = ($rgn << 28); $regions_used{$rgn} = 1; last; } } $config{memmap}{external_data_1} = sprintf("0x%08x", $config{memmap}{external_data_1}); #$config{memmap}{consoleio} = hex($config{memmap}{serialio}) + 0x100; #$config{memmap}{consoleio} = sprintf("0x%x", $config{memmap}{consoleio}); # Find an unused region for debug_sb_memory data for (my $rgn = 15;$rgn >= 0; $rgn--) { if (($rgn != hex($config{iccm}{iccm_region})) && ($rgn != hex($config{dccm}{dccm_region})) && ($rgn != (hex($config{memmap}{serialio})>>28)) && ($rgn != (hex($config{memmap}{external_data})>>28)) && ($rgn != (hex($config{memmap}{external_data_1})>>28)) && ($rgn != (hex($config{pic}{pic_region})))) { $config{memmap}{debug_sb_mem} = ($rgn << 28) + (22<<18); $regions_used{$rgn} = 1; last; } } $config{memmap}{debug_sb_mem} = sprintf("0x%08x", $config{memmap}{debug_sb_mem}); # Create the memory map hole for random testing # Only do this if masks are not enabled already if (hex($config{protection}{data_access_enable0}) > 0 || hex($config{protection}{data_access_enable1}) > 0 || hex($config{protection}{data_access_enable2}) > 0 || hex($config{protection}{data_access_enable3}) > 0 || hex($config{protection}{data_access_enable4}) > 0 || hex($config{protection}{data_access_enable5}) > 0 || hex($config{protection}{data_access_enable6}) > 0 || hex($config{protection}{data_access_enable7}) > 0 || hex($config{protection}{inst_access_enable0}) > 0 || hex($config{protection}{inst_access_enable1}) > 0 || hex($config{protection}{inst_access_enable2}) > 0 || hex($config{protection}{inst_access_enable3}) > 0 || hex($config{protection}{inst_access_enable4}) > 0 || hex($config{protection}{inst_access_enable5}) > 0 || hex($config{protection}{inst_access_enable6}) > 0 || hex($config{protection}{inst_access_enable7}) > 0 || $config{memmap}{external_mem_hole} eq "default disabled"){ delete($config{memmap}{external_mem_hole}) ; } else { # Unused region to create a memory map hole, if not already specified if ($config{memmap}{external_mem_hole} eq 'derived, overridable') { for (my $rgn = 15;$rgn >= 0; $rgn--) { if (!defined($regions_used{$rgn})) { $config{memmap}{external_mem_hole} = ($rgn << 28); $regions_used{$rgn} = 1; last; } } } else { my $rgn = hex($config{memmap}{external_mem_hole})>>28; $config{memmap}{external_mem_hole} = ($rgn << 28); $regions_used{$rgn} =1; } my $hreg = $config{memmap}{external_mem_hole}>>28; $config{protection}{data_access_addr0} = sprintf("0x%x", (($hreg^8)&8)<<28); $config{protection}{data_access_mask0} = "0x7fffffff"; $config{protection}{data_access_addr1} = sprintf("0x%x", ($hreg&8) << 28 |(($hreg^4)&4)<<28); $config{protection}{data_access_mask1} = "0x3fffffff"; $config{protection}{data_access_addr2} = sprintf("0x%x", ($hreg&12) <<28 | (($hreg^2)&2) <<28); $config{protection}{data_access_mask2} = "0x1fffffff"; $config{protection}{data_access_addr3} = sprintf("0x%x", ($hreg&14) << 28 |(($hreg^1)&1)<<28); $config{protection}{data_access_mask3} = "0x0fffffff"; $config{protection}{data_access_enable0} = "1"; $config{protection}{data_access_enable1} = "1"; $config{protection}{data_access_enable2} = "1"; $config{protection}{data_access_enable3} = "1"; $config{protection}{inst_access_addr0} = sprintf("0x%x", (($hreg^8)&8)<<28); $config{protection}{inst_access_mask0} = "0x7fffffff"; $config{protection}{inst_access_addr1} = sprintf("0x%x", ($hreg&8) << 28 |(($hreg^4)&4)<<28); $config{protection}{inst_access_mask1} = "0x3fffffff"; $config{protection}{inst_access_addr2} = sprintf("0x%x", ($hreg&12) <<28 | (($hreg^2)&2) <<28); $config{protection}{inst_access_mask2} = "0x1fffffff"; $config{protection}{inst_access_addr3} = sprintf("0x%x", ($hreg&14) << 28 |(($hreg^1)&1)<<28); $config{protection}{inst_access_mask3} = "0x0fffffff"; $config{protection}{inst_access_enable0} = "1"; $config{protection}{inst_access_enable1} = "1"; $config{protection}{inst_access_enable2} = "1"; $config{protection}{inst_access_enable3} = "1"; $config{memmap}{external_mem_hole} = sprintf("0x%08x", $config{memmap}{external_mem_hole}); } #Define 5 unused regions for used in TG my $unrg = 0; foreach my $unr (reverse(0 .. 15)) { if (!defined($regions_used{$unr})) { $config{memmap}{"unused_region$unrg"} = sprintf("0x%08x",($unr << 28)); $regions_used{$unr} = 1; $unrg++; } } if ($target eq "baseline") { $config{reset_vec} = $config{iccm}{iccm_sadr}; $config{testbench}{magellan} = 1; print "$self: Setting reset_vec = ICCM start address for Baseline\n"; } # Output bit-width specifiers for these variables our %widths = ( "dccm_region" => "4", "dccm_offset" => "28", "dccm_sadr" => "32", "dccm_eadr" => "32", "pic_region" => "4", "pic_offset" => "10", "pic_base_addr" => "32", "iccm_region" => "4", "iccm_offset" => "10", "iccm_sadr" => "32", "iccm_eadr" => "32", "bus_prty_default" => "2", "inst_access_enable0" => "1", "inst_access_enable1" => "1", "inst_access_enable2" => "1", "inst_access_enable3" => "1", "inst_access_enable4" => "1", "inst_access_enable5" => "1", "inst_access_enable6" => "1", "inst_access_enable7" => "1", "data_access_enable0" => "1", "data_access_enable1" => "1", "data_access_enable2" => "1", "data_access_enable3" => "1", "data_access_enable4" => "1", "data_access_enable5" => "1", "data_access_enable6" => "1", "data_access_enable7" => "1", ); #}}} my $d=$config{protection}{lockstep_enable}; if ($d==0 || !grep(/lockstep_enable=1/, @sets)) { delete $config{"protection"}{"lockstep_enable"}; } $c=$config{protection}{lockstep_delay}; if ($d==0 || ($c==0 && !grep(/lockstep_delay=/, @sets))) { delete $config{"protection"}{"lockstep_delay"}; } $c=$config{protection}{lockstep_regfile_enable}; if ($d==0 || ($c==0 || !grep(/lockstep_regfile_enable=/, @sets))) { delete $config{"protection"}{"lockstep_regfile_enable"}; } print "\nVeeR configuration for target=$target\n\n"; dump_define("","", \%config,[]); #print Dumper(\%config); #print Dumper(\%width); #print Dumper(\%sets); #print Dumper(\%unsets); # Sanity checks # Do not allow Smepmp to be enabled when user mode is disabled # TODO: Allowing this combination would require adding additional CSR decoder # variants. if(( $config{core}{user_mode} eq 0 ) && ( $config{protection}{smepmp} eq 1 )) { die "$self: ERROR! Currently Smepmp feature cannot be enabled when user mode support is disabled\n"; } check_addr_align("dccm", hex($config{dccm}{dccm_sadr}), $config{dccm}{dccm_size}*1024); check_addr_align("iccm", hex($config{iccm}{iccm_sadr}), $config{iccm}{iccm_size}*1024); check_addr_align("pic", hex($config{pic}{pic_base_addr}), $config{pic}{pic_size}*1024); # Prevent overlap of internal memories if ((hex($config{pic}{pic_region}) == hex($config{iccm}{iccm_region})) && (hex($config{pic}{pic_offset}) == hex($config{iccm}{iccm_offset}))) { die "$self: ERROR! PIC and ICCM blocks collide (region $config{iccm}{iccm_region}, offset $config{pic}{pic_offset})!\n"; } if ((hex($config{pic}{pic_region}) == hex($config{dccm}{dccm_region})) && (hex($config{pic}{pic_offset}) == hex($config{dccm}{dccm_offset}))) { die "$self: ERROR! PIC and DCCM blocks collide (region $config{dccm}{dccm_region}, offset $config{pic}{pic_offset})!\n"; } if ((hex($config{iccm}{iccm_region}) == hex($config{dccm}{dccm_region})) && (hex($config{iccm}{iccm_offset}) == hex($config{dccm}{dccm_offset}))) { die "$self: ERROR! ICCM and DCCM blocks collide (region $config{iccm}{iccm_region}, offset $config{dccm}{dccm_offset})!\n"; } #printf( "axi4 %s\n",$config{"testbench"}{"build_axi4"}); #printf( "ahb_lite %s\n",$config{"testbench"}{"build_ahb_lite"}); #printf( "axi_native %s\n",$config{"testbench"}{"build_axi_native"}); if( $target eq "el2_formal_axi" ) { $config{testbench}{build_axi_native} = 1; $config{testbench}{build_axi4} = 1; print( "\$config{testbench}{build_axi_native} = $config{testbench}{build_axi_native} \n" ); print( "\$config{testbench}{build_axi4 } = $config{testbench}{build_axi4 } \n" ); } if (($config{testbench}{build_ahb_lite} == 1)) { delete $config{testbench}{build_axi4}; $config{testbench}{build_axi_native}=1; $verilog_parms{build_axi4} = 0; } elsif (($config{testbench}{build_axi4} == 1)) { $config{testbench}{build_axi_native}=1; delete $config{testbench}{build_ahb_lite}; $verilog_parms{build_ahb_lite} = 0; } elsif (($config{testbench}{build_axi_native} == 1)) { die("illegal to set build_axi_native w/out build_axi4"); } #printf( "axi4 %s\n",$config{"testbench"}{"build_axi4"}); #printf( "ahb_lite %s\n",$config{"testbench"}{"build_ahb_lite"}); #printf( "axi_native %s\n",$config{"testbench"}{"build_axi_native"}); # Over-ride MFDC reset value for AXI. # Disable Bus barrier and 64b for AXI if (defined($config{"testbench"}{"build_axi_native"}) && ($config{"testbench"}{"build_axi_native"} ne "0")) { if (! (defined($config{testbench}{build_ahb_lite}) && $config{testbench}{build_ahb_lite} ne "0")) { $config{csr}{mfdc}{reset} = "0x00070040" if exists $config{csr}{mfdc}; } } # parm processing before any values are deleted from the hash delete $config{core}{fpga_optimize} if ($config{core}{fpga_optimize} == 0); delete $config{testbench}{openocd_test} if ($config{testbench}{openocd_test} == 0); # Remove TECH_SPECIFIC_* defines if they are set to 0 foreach my $key (sort keys(%config)) { if (grep(/tech_specific_/, $key)) { if ($config{$key} == 0) { delete $config{$key}; } } } print "$self: Writing $tdfile\n"; print "$self: Writing $paramfile\n"; open (FILE1, ">$tdfile") || die "Cannot open $tdfile for writing $!\n"; open (FILE2, ">$paramfile") || die "Cannot open $paramfile for writing $!\n"; print_header("//"); gen_define("","`", \%config, \%verilog_parms, \@verilog_vars); dump_parms(\%verilog_parms); close FILE1; close FILE2; $config{config_key}="32'hdeadbeef"; # end parms # deletes if (($load_to_use_plus1==0) && !grep(/load_to_use_plus1/, @sets)) { delete $config{"core"}{"load_to_use_plus1"}; } if (($iccm_enable==0) && !grep(/iccm_enable/, @sets)) { delete $config{"iccm"}{"iccm_enable"}; } # new code to handle the -set=parm=0 value correctly for common_defines.vh $c=$config{core}{user_mode}; if ($c==0 && !grep(/user_mode=1/, @sets)) { delete $config{"core"}{"user_mode"}; } $c=$config{core}{load_to_use_plus1}; if ($c==0 && !grep(/load_to_use_plus1=1/, @sets)) { delete $config{"core"}{"load_to_use_plus1"}; } $c=$config{core}{opensource}; if ($c==0 && !grep(/opensource=1/, @sets)) { delete $config{"core"}{"opensource"}; } $c=$config{core}{verilator}; if ($c==0 && !grep(/verilator=1/, @sets)) { delete $config{"core"}{"verilator"}; } $c=$config{core}{div_new}; if ($c==0 && !grep(/div_new=1/, @sets)) { delete $config{"core"}{"div_new"}; } # not needed #$c=$config{core}{div_bit}; if ($c==0 && !grep(/div_bit=1/, @sets)) { delete $config{"core"}{"div_bit"}; } $c=$config{iccm}{iccm_enable}; if ($c==0 && !grep(/iccm_enable=1/, @sets)) { delete $config{"iccm"}{"iccm_enable"}; } $c=$config{btb}{btb_enable}; if ($c==0 && !grep(/btb_enable=1/, @sets)) { delete $config{"btb"}{"btb_enable"}; } $c=$config{dccm}{dccm_enable}; if ($c==0 && !grep(/dccm_enable=1/, @sets)) { delete $config{"dccm"}{"dccm_enable"}; } $c=$config{icache}{icache_waypack}; if ($c==0 && !grep(/icache_waypack=1/, @sets)) { delete $config{"icache"}{"icache_waypack"}; } $c=$config{icache}{icache_enable}; if ($c==0 && !grep(/icache_enable=1/, @sets)) { delete $config{"icache"}{"icache_enable"}; } $c=$config{icache}{icache_2banks}; if ($c==0 && !grep(/icache_2banks=1/, @sets)) { delete $config{"icache"}{"icache_2banks"}; } $c=$config{pic}{pic_2cycle}; if ($c==0 && !grep(/pic_2cycle=1/, @sets)) { delete $config{"pic"}{"pic_2cycle"}; } $c=$config{btb}{btb_fullya}; if ($c==0 && !grep(/btb_fullya=1/, @sets)) { delete $config{"btb"}{"btb_fullya"}; } $c=$config{protection}{smepmp}; if ($c==0 && !grep(/smepmp=1/, @sets)) { delete $config{"protection"}{"smepmp"}; } if ($target eq "default") { } elsif (($config{"testbench"}{"build_axi4"} == 1)) { delete $config{"testbench"}{"build_ahb_lite"}; delete $config{"testbench"}{"build_axi_native_ahb"}; } elsif (($config{"testbench"}{"build_ahb_lite"} == 1)) { delete $config{"testbench"}{"build_axi4"}; delete $config{"testbench"}{"build_axi_native"}; delete $config{"testbench"}{"build_axi_native_ahb"}; } elsif (($config{"testbench"}{"build_axi_native_ahb"} == 1)) { delete $config{"testbench"}{"build_axi4"}; delete $config{"testbench"}{"build_axi_native_ahb"}; } elsif (($config{"testbench"}{"build_axi_native"} == 1)) { die("illegal to set build_axi_native w/out build_axi4"); } else { delete $config{"testbench"}{"build_ahb_lite"}; delete $config{"testbench"}{"build_axi4"}; delete $config{"testbench"}{"build_axi_native"}; delete $config{"testbench"}{"build_axi_native_ahb"}; } ##################### Add dumper routines here ########################## # # Dump Verilog $RV_ROOT/configs/common_defines.vh print "$self: Writing $vlogfile\n"; open (FILE, ">$vlogfile") || die "Cannot open $vlogfile for writing $!\n"; print_header("//"); begin_include_guard(\*FILE, "`", "COMMON_DEFINES"); print FILE "`define RV_ROOT \"".$ENV{RV_ROOT}."\"\n"; gen_define("","`", \%config, "", \@verilog_vars); end_include_guard(\*FILE, "`", "COMMON_DEFINES"); close FILE; print "$self: Writing $asmfile\n"; open (FILE, ">$asmfile") || die "Cannot open $asmfile for writing $!\n"; # Dump ASM/C $RV_ROOT/diags/env/defines.h print_header("//"); begin_include_guard(\*FILE, "#", "DEFINES"); gen_define("","#", \%config, "", \@asm_vars, \@asm_overridable); end_include_guard(\*FILE, "#", "DEFINES"); close FILE; # add `define PHYSICAL 1 # remove `undef RV_ICCM_ENABLE my $pddata=' `include "common_defines.vh" `undef TEC_RV_ICG `define RV_PHYSICAL 1 '; print "$self: Writing $pdfile\n"; open (FILE, ">$pdfile") || die "Cannot open $pdfile for writing $!\n"; # Dump PD $RV_ROOT/$RV_ROOT/configs/pd_defines.vh print_header("//"); printf (FILE "$pddata"); close FILE; print "$self: Writing $whisperfile\n"; dump_whisper_config(\%config, $whisperfile); # PIC address map based on config `$ENV{RV_ROOT}/tools/picmap -t $config{pic}{pic_total_int} > $build_path/pic_map_auto.h`; # Perl vars for use by scripts print "$self: Writing $perlfile\n"; open (FILE, ">$perlfile") || die "Cannot open $perlfile for writing $!\n"; print_header("# "); print FILE "# To use this in a perf script, use 'require \$RV_ROOT/configs/config.pl'\n"; print FILE "# Reference the hash via \$config{name}..\n\n\n"; print FILE Data::Dumper->Dump([\%config], [ qw(*config) ]); print FILE "1;\n"; close FILE; # Default linker script gen_default_linker_script(); # Done ################################################################## # exit(0); # ###################### Helper subroutines ##########################{{{ # Convert size in kilobytes to real value sub size {#{{{ my $ksize = shift; my $size = sprintf("%d",$ksize*1024); return $size; }#}}} # Print the defines with prefix sub print_define {#{{{ my ($sym, $key,$value, $override) = @_; my $lprefix = $prefix if ($key !~ /$no_prefix/); if ($sym eq "`") { if (defined($widths{$key})) { $value =~ s/^(0x)*/$widths{$key}'h/; } else { $value =~ s/^0x/'h/; } } if ($defines_case eq "U") { print FILE "${sym}ifndef \U$lprefix$key\E\n" if ($override); print FILE "${sym}define \U$lprefix$key\E $value\n"; print FILE "${sym}endif\n" if ($override); } else { print FILE "${sym}ifndef $lprefix$key\n" if ($override); print FILE "${sym}define $lprefix$key $value\n"; print FILE "${sym}endif\n" if ($override); } }#}}} # print header sub print_header {#{{{ my $cs = shift; print FILE "$cs NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE\n"; print FILE "$cs This is an automatically generated file by $ENV{USER} on ",`date`; print FILE "$cs\n$cs cmd: $self @argv_orig \n"; print FILE "$cs\n"; }#}}} # Begins include guard sub begin_include_guard { my ($fh, $sym, $name) = @_; print $fh "${sym}ifndef $prefix$name\n"; print $fh "${sym}define $prefix$name\n\n"; } # Ends include guard sub end_include_guard { my ($fh, $sym, $name) = @_; print $fh "\n${sym}endif // $prefix$name\n"; } # evaluate derivations sub derive {#{{{ my $eqn = shift; return sprintf("0x%x", eval($eqn)); }#}}} # traverse the database and extract the key/value pair sub gen_define {#{{{ my $matched = shift; my $prefix = shift; my $hash = @_[0]; my $parms = @_[1]; my @printvars = @{@_[2]}; my @overridable = @{@_[3]} if defined @_[3]; my $re = join("|",@printvars); $re = qr/($re)/; #print Dumper($hash); foreach my $key (sort keys %$hash) { next if $key eq "csr"; #print "looking at $key:$matched ($re)\n"; if (defined($unsets{$key})) { print "$self:unsetting $key\n"; delete($config{$key}); if ($parms and defined($parms->{$key})) { $parms->{$key} = 0; } next } if (defined($sets{$key}) && $sets{$key} ne $$hash{$key}) { if (($$hash{$key} =~ /derived/i) && ($$hash{$key} !~ /overridable/i)) { die ("$self: ERROR! $key is a derived and non-overridable parameter!\n"); } else { print "$self: Overriding $key value $$hash{$key} with $sets{$key}\n"; $$hash{$key} = $sets{$key}; } } my $value = $$hash{$key}; if (ref($value) eq "HASH") { if ($key =~ /$re/) { $matched = 1; } gen_define($matched,$prefix, $value, $parms, \@printvars, \@overridable); $matched = 0; } elsif (ref($value) eq "ARRAY") { # print "$key : @{$value}\n"; $matched = 0; } else { if ($matched eq "1" || $key =~ /$re/) { if($value =~ /derive\(.*\)/o) { $value = eval($value); } my $override = grep(/^$key$/, @overridable); print_define($prefix, $key, $value, $override) if ($value !~ /derived/); #printf("$key = $value\n"); if ($parms and defined($parms->{$key})) { $value=decimal($value); #printf("verilog parm $key = $value %s\n",$parms->{$key}); $value=d2b($key,$value,$parms->{$key}); #printf("verilog parm $key = $value\n"); $parms->{$key}=$value; } } } } }#}}} sub dump_define {#{{{ my $matched = shift; my $prefix = shift; my $hash = @_[0]; my @printvars = @{@_[1]}; my @overridable = @{@_[2]} if defined @_[2]; my $re = join("|",@printvars); $re = qr/($re)/; #print Dumper($hash); foreach my $key (sort keys %$hash) { next if $key eq "csr"; next unless $matched || grep(/^$key$/,@dvars); #print "looking at $key:$matched ($re)\n"; if (defined($unsets{$key})) { print "$self:unsetting $key\n"; delete($config{$key}); next } if (defined($sets{$key}) && $sets{$key} ne $$hash{$key}) { if (($$hash{$key} =~ /derived/i) && ($$hash{$key} !~ /overridable/i)) { die ("$self: ERROR! $key is a derived and non-overridable parameter!\n"); } else { print "$self: Overriding $key value $$hash{$key} with $sets{$key}\n"; $$hash{$key} = $sets{$key}; } } my $value = $$hash{$key}; if (ref($value) eq "HASH") { if ($key =~ /$re/) { $matched = 1; } dump_define($matched,$prefix, $value, \@printvars, \@overridable); $matched = 0; } elsif (ref($value) eq "ARRAY") { # print "$key : @{$value}\n"; $matched = 0; } else { if ($matched eq "1" || $key =~ /$re/) { if($value =~ /derive\(.*\)/o) { $value = eval($value); } printf ("veer: %-30s = $value\n",$key) if ($value !~ /derived/); } } } }#}}} # Perform cmd line set/unset ############################################{{{ sub map_set_unset { if (scalar(@sets)) { print "$self: Set(s) requested : @sets\n"; foreach (@sets) { my ($key,$value) = m/(\w+)=*(\w+)*/o; $value = 1 if (!defined($value)); $sets{$key} = $value; } } if (scalar(@unsets)) { print "$self: Unset(s) requested : @unsets\n"; foreach (@unsets) { $unsets{$_} = 1; } } } #}}} #}}} # If arg looks like a hexadecimal string, then convert it to decimal.#{{{ # Otherwise, return arg. sub decimal { my ($x) = @_; return hex($x) if $x =~ /^0x/o; return $x; }#}}} # Collect memory protection specs (array of address pairs) in the given # resutls array. Tag is either "data" or "inst". sub collect_mem_protection {#{{{ my ($tag, $config, $results) = @_; return unless exists $config{protection}; my $prot = $config{protection}; my $enable_tag = $tag . "_access_enable"; my $addr_tag = $tag . "_access_addr"; my $mask_tag = $tag . "_access_mask"; foreach my $key (sort keys %{$prot}) { next unless $key =~ /^$enable_tag(\d+)$/; my $ix = $1; my $enable = $prot->{$key}; if ($enable !~ /[01]$/) { warn("Invalid value for protection entry $key: $enable\n"); next; } next unless ($enable eq "1" or $enable eq "1'b1"); if (! exists $prot->{"$addr_tag$ix"}) { warn("Missing $addr_tag$ix\n"); next; } if (! exists $prot->{"$mask_tag$ix"}) { warn("Missing $mask_tag$ix\n"); next; } my $addr = $prot->{"$addr_tag$ix"}; my $mask = $prot->{"$mask_tag$ix"}; if ($addr !~ /^0x[0-9a-fA-F]+$/) { warn("Invalid $addr_tag$ix: $addr\n"); next; } if ($mask !~ /^0x[0-9a-fA-F]+$/) { warn("Invalid $mask_tag$ix: $mask\n"); next; } if ((hex($addr) & hex($mask)) != 0) { warn("Protection mask bits overlap address bits in $tag mask $mask and addr $addr\n"); } if ($mask !~ /^0x0*[137]?f*$/) { warn("Protection $tag mask ($mask) must have all its one bits to the right of its zero bits\n"); next; } my $start = hex($addr) & ~hex($mask) & 0xffffffff; my $end = (hex($addr) | hex($mask)) & 0xffffffff; $start = sprintf("0x%08x", $start); $end = sprintf("0x%08x", $end); push(@{$results}, [ $start, $end ]); } }#}}} # Collect the memory mapped registers associated with the pic (platform # interrup controller) to include in the whisper.json file. sub collect_mem_mapped_regs {#{{{ my ($pic, $results) = @_; my $default_mask = 0; $results->{default_mask} = $default_mask; my $addr = hex($pic->{pic_region})*256*1024*1024 + hex($pic->{pic_offset}); $results->{address} = sprintf("0x%x", $addr); $results->{size} = sprintf("0x%x", $pic->{pic_size}*1024); my @names = qw ( mpiccfg meipl meip meie meigwctrl meigwclr meidels ); $results->{registers} = {}; foreach my $name (@names) { my $tag = "pic_${name}_offset"; next unless exists $pic->{$tag}; my %item; my $offset = hex($pic->{$tag}); $offset += 4 if ($name ne 'mpiccfg' and $name ne 'meip'); $item{address} = sprintf("0x%x", $addr + $offset); $item{mask} = $pic->{"pic_${name}_mask"}; $item{count} = $pic->{"pic_${name}_count"}; $results->{registers}{$name} = \%item; } }#}}} sub dump_whisper_config{#{{{ my ($config, $path) = @_; open(my $fh, ">", "$path") or die ("Failed to open $path for writing: $!\n"); # Put the configuration parameters relevant to whisper into a hash # in preparation for a JSON dump. my %jh; # Json hash # Collect top-level integer entries. foreach my $tag (qw( harts xlen )) { $jh{$tag} = $config{$tag} + 0 if exists $config{$tag}; } # Collect top-level string/hex entries. foreach my $tag (qw ( reset_vec nmi_vec num_mmode_perf_regs max_mmode_perf_event even_odd_trigger_chains)) { $jh{$tag} = $config{$tag} if exists $config{$tag}; } # Collect memory map configs. my (@inst_mem_prot, @data_mem_prot); collect_mem_protection("inst", $config, \@inst_mem_prot); collect_mem_protection("data", $config, \@data_mem_prot); $jh{memmap}{inst} = [@inst_mem_prot] if @inst_mem_prot; $jh{memmap}{data} = [@data_mem_prot] if @data_mem_prot; $config{memmap}{consoleio} = $config{memmap}{serialio} if exists $config{memmap}{serialio}; foreach my $tag (qw ( size page_size serialio consoleio)) { $jh{memmap}{$tag} = $config{memmap}{$tag} if exists $config{memmap}{$tag}; } # Collect load/store-error rollback parameter. if (exists $config{testbench} and exists $config{testbench}{sterr_rollback}) { $jh{store_error_rollback} = $config{testbench}{sterr_rollback}; } if (exists $config{testbench} and exists $config{testbench}{lderr_rollback}) { $jh{load_error_rollback} = $config{testbench}{lderr_rollback}; } # Collect dccm configs if (exists $config{dccm} and $config{dccm}{dccm_enable}) { $jh{dccm}{region} = $config{dccm}{dccm_region}; $jh{dccm}{size} = 1024*decimal($config{dccm}{dccm_size}); # From 1k to bytes $jh{dccm}{offset} = $config{dccm}{dccm_offset}; $jh{dccm}{size} = sprintf("0x%x", $jh{dccm}{size}); } # Collect icccm configs. if (exists $config{iccm} and $config{iccm}{iccm_enable}) { $jh{iccm}{region} = $config{iccm}{iccm_region}; $jh{iccm}{size} = 1024*decimal($config{iccm}{iccm_size}); # From 1k to bytes $jh{iccm}{offset} = $config{iccm}{iccm_offset}; $jh{iccm}{size} = sprintf("0x%x", $jh{iccm}{size}); } # Collect CSRs $jh{csr} = $config{csr} if exists $config{csr}; # Collect CSRs not included in verilog. my @removed_csrs; if (! $config{core}{timer_legal_en}) { push(@removed_csrs, $_) for qw (mitcnt0 mitbnd0 mitctl0 mitcnt1 mitbnd1 mitctl1); } # Collect fast interrupt enable. if (exists $config{core}{fast_interrupt_redirect}) { $jh{fast_interrupt_redirect} = $config{core}{fast_interrupt_redirect}; # meicpct CSR is not built if fast interrupt. push(@removed_csrs, 'meicpct') if $jh{fast_interrupt_redirect}; } # Remove CSRs not configured into verilog. delete $jh{csr}{$_} foreach @removed_csrs; # Collect zb extension configs $jh{enable_zbb} = $config{core}{bitmanip_zbb}; $jh{enable_zbs} = $config{core}{bitmanip_zbs}; $jh{enable_zba} = $config{core}{bitmanip_zba}; $jh{enable_zbc} = $config{core}{bitmanip_zbc}; $jh{enable_zbe} = $config{core}{bitmanip_zbe}; $jh{enable_zbf} = $config{core}{bitmanip_zbf}; $jh{enable_zbp} = $config{core}{bitmanip_zbp}; $jh{enable_zbr} = $config{core}{bitmanip_zbr}; # Collect pic configs. if (exists $config{pic}) { my %mem_mapped; collect_mem_mapped_regs($config{pic}, \%mem_mapped); $jh{'memory_mapped_registers'} = \%mem_mapped; } # Collect performance events. Uncomment when RTL ready. if (exists $config{perf_events}) { $jh{mmode_perf_events} = $config{perf_events}; } # Make atomic instructions illegal outside of DCCM. $jh{amo_illegal_outside_dccm} = "true"; # Make ld/st instructions trigger misaligned exceptions if base # address (value in rs1) and effective address refer to regions of # different types. $jh{effective_address_compatible_with_base} = "true"; # Collect triggers. $jh{triggers} = $config{triggers} if exists $config{triggers}; # Dump JSON config file. my $json = JSON->new->allow_nonref; my $text = $json->pretty->encode(\%jh); print($fh $text); close $fh; }#}}} # Checker for iccm/dccm/pic sub-region address alignment. Address must be a multiple # of size or next higher power of 2 if size is not a power of 2. sub check_addr_align {#{{{ my ($section, $addr, $size) = @_; die("Invalid $section size: $size\n") if $size <= 0; my $log_size = log2($size); my $p2 = 1 << $log_size; $size = 2*$p2 if $size != $p2; if (($addr % $size) != 0) { printf("Address of $section area(0x%x) is not a multiple of its size (0x%x)\n", $addr, $size); exit(1); } }#}}} sub log2 {#{{{ my ($n) = @_; return log($n)/log(2); }#}}} sub b2d {#{{{ my ($v) = @_; $v = oct("0b" . $v); return($v); }#}}} sub d2b {#{{{ my ($key,$v,$LEN) = @_; my $repeat; $v = sprintf "%b",$v; if (length($v)<$LEN) { $repeat=$LEN-length($v); $v="0"x$repeat.$v; } elsif (length($v)>$LEN) { die("d2b: parm $key value $v > len $LEN"); } return($v); }#}}} sub invalid_mask {#{{{ my ($m) = @_; if ($m =~ /^0x(0)*([137]?f+)$/) { return(0); } return(1); }#}}} sub b2h {#{{{ my ($bin) = @_; # Make input bit string a multiple of 4 $bin = substr("0000",length($bin)%4) . $bin if length($bin)%4; my ($hex, $nybble) = (""); while (length($bin)) { ($nybble,$bin) = (substr($bin,0,4), substr($bin,4)); $nybble = eval "0b$nybble"; $hex .= substr("0123456789ABCDEF", $nybble, 1); } return $hex; }#}}} # BHT index is a hash of the GHR and PC_HASH sub ghrhash{#{{{ my($btb_index_hi,$ghr_size) = @_; $btb_size = $btb_index_hi - 1; my $ghr_hi = $ghr_size - 1; my $ghr_lo = $btb_size; my $ghr_start = "{"; if($ghr_size > $btb_size){ return "{ghr[$ghr_hi:$ghr_lo], hashin[$btb_index_hi:2]^ghr[$ghr_lo-1:0]} // cf1"; } else { return "{hashin[$ghr_size+1:2]^ghr[$ghr_size-1:0]}// cf2"; } }#}}} sub dump_parms {#{{{ my ($hash) = @_; my ($bvalue, $blen, $upper); printf(FILE1 "typedef struct packed {\n"); foreach my $key (sort keys %$hash) { $bvalue=$hash->{$key}; $blen=length($bvalue); $upper=$key; $upper=~ tr/a-z/A-Z/; if ($blen==1) { printf(FILE1 "\tlogic %-10s $upper;\n"); } else { printf(FILE1 "\tlogic %-10s $upper;\n",sprintf("[%d:0]",$blen-1)); } } printf(FILE1 "} el2_param_t;\n\n"); my $bcat=""; my $parmcnt=0; foreach my $key (sort keys %$hash) { #printf("// $key = %s\n",$verilog_parms{$key}); $bcat.=$hash->{$key}; $parmcnt++; } my $bvalue=""; my $pcnt=0; my $delim=","; my $msb; printf(FILE2 "// parameter el2_param_t pt = '{\n"); foreach my $key (sort keys %$hash) { $upper=$key; $upper=~ tr/a-z/A-Z/; $pcnt++; if ($pcnt==$parmcnt) { undef $delim; } if ($hash->{$key} eq "0") { $hash->{$key}="0000"; } if (length($hash->{$key}) != 1) { $msb=substr($hash->{$key},0,4); # require upper 4b to be 0 if ($msb ne "0000") { die("parameter $upper upper 4b must be 0"); } } printf(FILE2 "// \t%-22s : %d\'h%-10s $delim\n",$upper,length($hash->{$key}),b2h($hash->{$key})); } printf(FILE2 "// }\n"); printf(FILE2 "parameter el2_param_t pt = %d'h%s\n",length($bcat),b2h($bcat)); }#}}} sub gen_default_linker_script {#{{{ open (FILE, ">$linkerfile") || die "Cannot open $linkerfile for writing $!\n"; print "$self: Writing $linkerfile\n"; print FILE "/*\n"; print_header(); my $io = "0xd0580000"; $io = $config{memmap}{serialio} if exists $config{memmap}{serialio}; my $iccm = ""; my $iccm_ctl = ""; if (exists $config{iccm} and $config{iccm}{iccm_enable} and $text_in_iccm) { my $sa = $config{iccm}{iccm_sadr}; my $ea = $config{iccm}{iccm_eadr}; $iccm = " . = $sa ;"; $iccm_ctl = " . = 0xfffffff0; .iccm.ctl . : { LONG($sa); LONG($ea) }" ; } my $sa = $config{memmap}{external_data}; my $dccm_ctl = ""; if (exists $config{dccm} and $config{dccm}{dccm_enable}) { $sa = $config{dccm}{dccm_sadr}; $dccm_ctl = " . = 0xfffffff8; .data.ctl : { LONG($sa); LONG(STACK) }" ; } my $data_loc = " . = $sa ;"; print FILE "*/\n"; print FILE <<"EOF"; OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = $config{reset_vec}; .text.init . : { *(.text.init) } $iccm .text . : { *(.text) } _end = .; . = $io; .data.io . : { *(.data.io) } $data_loc .data : ALIGN(0x800) { *(.*data) *(.rodata*)} .bss : {BSS_START = .; *(.*bss)} BSS_END = .; STACK = ALIGN(16) + 0x1000; $iccm_ctl $dccm_ctl } EOF close FILE; } #}}} ================================================ FILE: configs/veer_config_gen.py ================================================ #!/usr/bin/env python3 from fusesoc.capi2.generator import Generator import os import subprocess import sys class VeerConfigGenerator(Generator): def run(self): script_root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..')) files = [ {"common_defines.vh" : { "copyto" : "config/common_defines.vh", "file_type" : "systemVerilogSource"}}, {"el2_pdef.vh" : { "copyto" : "config/el2_pdef.vh", "file_type" : "systemVerilogSource"}}, {"el2_param.vh" : { "is_include_file" : True, "file_type" : "systemVerilogSource"}}, {"pic_map_auto.h" : { "is_include_file" : True, "file_type" : "systemVerilogSource"}}] env = os.environ.copy() env['RV_ROOT'] = script_root env['BUILD_PATH'] = os.getcwd() args = ['configs/veer.config'] + self.config.get('args', []) rc = subprocess.call(args, cwd=script_root, env=env, stdout=subprocess.DEVNULL) if rc: exit(1) filenames = [] for f in files: for k in f: filenames.append(k) self.add_files(files) g = VeerConfigGenerator() g.run() g.write() ================================================ FILE: design/dbg/el2_dbg.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // Function: Top level VeeR core file to control the debug mode // Comments: Responsible to put the rest of the core in quiesce mode, // Send the commands/address. sends WrData and Recieve read Data. // And then Resume the core to do the normal mode // Author : //******************************************************************************** module el2_dbg import el2_pkg::*; #( `include "el2_param.vh" )( // outputs to the core for command and data interface output logic [31:0] dbg_cmd_addr, output logic [31:0] dbg_cmd_wrdata, output logic dbg_cmd_valid, output logic dbg_cmd_write, // 1: write command, 0: read_command output logic [1:0] dbg_cmd_type, // 0:gpr 1:csr 2: memory output logic [1:0] dbg_cmd_size, // size of the abstract mem access debug command output logic dbg_core_rst_l, // core reset from dm // inputs back from the core/dec input logic [31:0] core_dbg_rddata, input logic core_dbg_cmd_done, // This will be treated like a valid signal input logic core_dbg_cmd_fail, // Exception during command run // Signals to dma to get a bubble output logic dbg_dma_bubble, // Debug needs a bubble to send a valid input logic dma_dbg_ready, // DMA is ready to accept debug request // interface with the rest of the core to halt/resume handshaking output logic dbg_halt_req, // This is a pulse output logic dbg_resume_req, // Debug sends a resume requests. Pulse input logic dec_tlu_debug_mode, // Core is in debug mode input logic dec_tlu_dbg_halted, // The core has finished the queiscing sequence. Core is halted now input logic dec_tlu_mpc_halted_only, // Only halted due to MPC input logic dec_tlu_resume_ack, // core sends back an ack for the resume (pulse) // inputs from the JTAG input logic dmi_reg_en, // read or write input logic [6:0] dmi_reg_addr, // address of DM register input logic dmi_reg_wr_en, // write instruction input logic [31:0] dmi_reg_wdata, // write data // output output logic [31:0] dmi_reg_rdata, // read data // AXI Write Channels output logic sb_axi_awvalid, input logic sb_axi_awready, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [pt.SB_BUS_TAG-1:0] sb_axi_awid, /*pragma coverage on*/ output logic [31:0] sb_axi_awaddr, output logic [3:0] sb_axi_awregion, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [7:0] sb_axi_awlen, /*pragma coverage on*/ output logic [2:0] sb_axi_awsize, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [1:0] sb_axi_awburst, output logic sb_axi_awlock, output logic [3:0] sb_axi_awcache, output logic [2:0] sb_axi_awprot, output logic [3:0] sb_axi_awqos, /*pragma coverage on*/ output logic sb_axi_wvalid, input logic sb_axi_wready, output logic [63:0] sb_axi_wdata, output logic [7:0] sb_axi_wstrb, output logic sb_axi_wlast, input logic sb_axi_bvalid, output logic sb_axi_bready, input logic [1:0] sb_axi_bresp, // AXI Read Channels output logic sb_axi_arvalid, input logic sb_axi_arready, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [pt.SB_BUS_TAG-1:0] sb_axi_arid, /*pragma coverage on*/ output logic [31:0] sb_axi_araddr, output logic [3:0] sb_axi_arregion, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [7:0] sb_axi_arlen, /*pragma coverage on*/ output logic [2:0] sb_axi_arsize, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [1:0] sb_axi_arburst, output logic sb_axi_arlock, output logic [3:0] sb_axi_arcache, output logic [2:0] sb_axi_arprot, output logic [3:0] sb_axi_arqos, /*pragma coverage on*/ input logic sb_axi_rvalid, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic sb_axi_rready, /*pragma coverage on*/ input logic [63:0] sb_axi_rdata, input logic [1:0] sb_axi_rresp, input logic dbg_bus_clk_en, // general inputs input logic clk, input logic free_clk, input logic rst_l, // This includes both top rst and debug rst input logic dbg_rst_l, input logic clk_override, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); typedef enum logic [3:0] {IDLE=4'h0, HALTING=4'h1, HALTED=4'h2, CORE_CMD_START=4'h3, CORE_CMD_WAIT=4'h4, SB_CMD_START=4'h5, SB_CMD_SEND=4'h6, SB_CMD_RESP=4'h7, CMD_DONE=4'h8, RESUMING=4'h9} state_t; typedef enum logic [3:0] {SBIDLE=4'h0, WAIT_RD=4'h1, WAIT_WR=4'h2, CMD_RD=4'h3, CMD_WR=4'h4, CMD_WR_ADDR=4'h5, CMD_WR_DATA=4'h6, RSP_RD=4'h7, RSP_WR=4'h8, DONE=4'h9} sb_state_t; state_t dbg_state; state_t dbg_nxtstate; logic dbg_state_en; // these are the registers that the debug module implements logic [31:0] dmstatus_reg; // [26:24]-dmerr, [17:16]-resume ack, [9:8]-halted, [3:0]-version logic [31:0] dmcontrol_reg; // dmcontrol register has only 6 bits implemented. 31: haltreq, 30: resumereq, 29: haltreset, 28: ackhavereset, 1: ndmreset, 0: dmactive. logic [31:0] command_reg; logic [31:0] abstractcs_reg; // bits implemted are [12] - busy and [10:8]= command error logic [31:0] haltsum0_reg; logic [31:0] data0_reg; logic [31:0] data1_reg; // data 0 logic [31:0] data0_din; logic data0_reg_wren, data0_reg_wren0, data0_reg_wren1, data0_reg_wren2; // data 1 logic [31:0] data1_din; logic data1_reg_wren, data1_reg_wren0, data1_reg_wren1; // abstractcs logic abstractcs_busy_wren; logic abstractcs_busy_din; logic [2:0] abstractcs_error_din; logic abstractcs_error_sel0, abstractcs_error_sel1, abstractcs_error_sel2, abstractcs_error_sel3, abstractcs_error_sel4, abstractcs_error_sel5, abstractcs_error_sel6; logic dbg_sb_bus_error; // abstractauto logic abstractauto_reg_wren; logic [1:0] abstractauto_reg; // dmstatus logic dmstatus_resumeack_wren; logic dmstatus_resumeack_din; logic dmstatus_haveresetn_wren; logic dmstatus_resumeack; logic dmstatus_unavail; logic dmstatus_running; logic dmstatus_halted; logic dmstatus_havereset, dmstatus_haveresetn; // dmcontrol logic resumereq; logic dmcontrol_wren, dmcontrol_wren_Q; // command logic execute_command_ns, execute_command; logic command_wren, command_regno_wren; logic command_transfer_din; logic command_postexec_din; logic [31:0] command_din; logic [3:0] dbg_cmd_addr_incr; logic [31:0] dbg_cmd_curr_addr; logic [31:0] dbg_cmd_next_addr; // needed to send the read data back for dmi reads logic [31:0] dmi_reg_rdata_din; sb_state_t sb_state; sb_state_t sb_nxtstate; logic sb_state_en; //System bus section logic sbcs_wren; logic sbcs_sbbusy_wren; logic sbcs_sbbusy_din; logic sbcs_sbbusyerror_wren; logic sbcs_sbbusyerror_din; logic sbcs_sberror_wren; logic [2:0] sbcs_sberror_din; logic sbcs_unaligned; logic sbcs_illegal_size; logic [19:15] sbcs_reg_int; // data logic sbdata0_reg_wren0; logic sbdata0_reg_wren1; logic sbdata0_reg_wren; logic [31:0] sbdata0_din; logic sbdata1_reg_wren0; logic sbdata1_reg_wren1; logic sbdata1_reg_wren; logic [31:0] sbdata1_din; logic sbaddress0_reg_wren0; logic sbaddress0_reg_wren1; logic sbaddress0_reg_wren; logic [31:0] sbaddress0_reg_din; logic [3:0] sbaddress0_incr; logic sbreadonaddr_access; logic sbreadondata_access; logic sbdata0wr_access; logic sb_abmem_cmd_done_in, sb_abmem_data_done_in; logic sb_abmem_cmd_done_en, sb_abmem_data_done_en; logic sb_abmem_cmd_done, sb_abmem_data_done; logic [31:0] abmem_addr; logic abmem_addr_in_dccm_region, abmem_addr_in_iccm_region, abmem_addr_in_pic_region; logic abmem_addr_core_local; logic abmem_addr_external; logic sb_cmd_pending, sb_abmem_cmd_pending; logic sb_abmem_cmd_write; logic [2:0] sb_abmem_cmd_size; logic [31:0] sb_abmem_cmd_addr; logic [31:0] sb_abmem_cmd_wdata; logic [2:0] sb_cmd_size; logic [31:0] sb_cmd_addr; logic [63:0] sb_cmd_wdata; logic sb_bus_cmd_read, sb_bus_cmd_write_addr, sb_bus_cmd_write_data; logic sb_bus_rsp_read, sb_bus_rsp_write; logic sb_bus_rsp_error; logic [63:0] sb_bus_rdata; //registers logic [31:0] sbcs_reg; logic [31:0] sbaddress0_reg; logic [31:0] sbdata0_reg; logic [31:0] sbdata1_reg; logic sb_abmem_cmd_arvalid, sb_abmem_cmd_awvalid, sb_abmem_cmd_wvalid; logic sb_abmem_read_pend; logic sb_cmd_awvalid, sb_cmd_wvalid, sb_cmd_arvalid; logic sb_read_pend; logic [31:0] sb_axi_addr; logic [63:0] sb_axi_wrdata; logic [2:0] sb_axi_size; logic dbg_dm_rst_l; logic rst_l_sync; //clken logic dbg_free_clken; logic dbg_free_clk; logic sb_free_clken; logic sb_free_clk; // clocking // used for the abstract commands. assign dbg_free_clken = dmi_reg_en | execute_command | (dbg_state != IDLE) | dbg_state_en | dec_tlu_dbg_halted | dec_tlu_mpc_halted_only | dec_tlu_debug_mode | dbg_halt_req | clk_override; // used for the system bus assign sb_free_clken = dmi_reg_en | execute_command | sb_state_en | (sb_state != SBIDLE) | clk_override; rvoclkhdr dbg_free_cgc (.en(dbg_free_clken), .l1clk(dbg_free_clk), .*); rvoclkhdr sb_free_cgc (.en(sb_free_clken), .l1clk(sb_free_clk), .*); // end clocking section // Reset logic assign dbg_dm_rst_l = dbg_rst_l & (dmcontrol_reg[0] | scan_mode); assign dbg_core_rst_l = ~dmcontrol_reg[1] | scan_mode; // synchronize the rst rvsyncss #(1) rstl_syncff (.din(rst_l), .dout(rst_l_sync), .clk(free_clk), .rst_l(dbg_rst_l)); // system bus register // sbcs[31:29], sbcs - [22]:sbbusyerror, [21]: sbbusy, [20]:sbreadonaddr, [19:17]:sbaccess, [16]:sbautoincrement, [15]:sbreadondata, [14:12]:sberror, sbsize=32, 128=0, 64/32/16/8 are legal assign sbcs_reg[31:29] = 3'b1; assign sbcs_reg[28:23] = '0; assign sbcs_reg[19:15] = {sbcs_reg_int[19], ~sbcs_reg_int[18], sbcs_reg_int[17:15]}; assign sbcs_reg[11:5] = 7'h20; assign sbcs_reg[4:0] = 5'b01111; assign sbcs_wren = (dmi_reg_addr == 7'h38) & dmi_reg_en & dmi_reg_wr_en & (sb_state == SBIDLE); assign sbcs_sbbusyerror_wren = (sbcs_wren & dmi_reg_wdata[22]) | (sbcs_reg[21] & dmi_reg_en & ((dmi_reg_wr_en & (dmi_reg_addr == 7'h39)) | (dmi_reg_addr == 7'h3c) | (dmi_reg_addr == 7'h3d))); assign sbcs_sbbusyerror_din = ~(sbcs_wren & dmi_reg_wdata[22]); // Clear when writing one rvdffs #(1) sbcs_sbbusyerror_reg (.din(sbcs_sbbusyerror_din), .dout(sbcs_reg[22]), .en(sbcs_sbbusyerror_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk)); rvdffs #(1) sbcs_sbbusy_reg (.din(sbcs_sbbusy_din), .dout(sbcs_reg[21]), .en(sbcs_sbbusy_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk)); rvdffs #(1) sbcs_sbreadonaddr_reg (.din(dmi_reg_wdata[20]), .dout(sbcs_reg[20]), .en(sbcs_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk)); rvdffs #(5) sbcs_misc_reg (.din({dmi_reg_wdata[19],~dmi_reg_wdata[18],dmi_reg_wdata[17:15]}), .dout(sbcs_reg_int[19:15]), .en(sbcs_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk)); rvdffs #(3) sbcs_error_reg (.din(sbcs_sberror_din[2:0]), .dout(sbcs_reg[14:12]), .en(sbcs_sberror_wren), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk)); assign sbcs_unaligned = ((sbcs_reg[19:17] == 3'b001) & sbaddress0_reg[0]) | ((sbcs_reg[19:17] == 3'b010) & (|sbaddress0_reg[1:0])) | ((sbcs_reg[19:17] == 3'b011) & (|sbaddress0_reg[2:0])); assign sbcs_illegal_size = sbcs_reg[19]; // Anything bigger than 64 bits is illegal assign sbaddress0_incr[3:0] = ({4{(sbcs_reg[19:17] == 3'h0)}} & 4'b0001) | ({4{(sbcs_reg[19:17] == 3'h1)}} & 4'b0010) | ({4{(sbcs_reg[19:17] == 3'h2)}} & 4'b0100) | ({4{(sbcs_reg[19:17] == 3'h3)}} & 4'b1000); // sbdata assign sbdata0_reg_wren0 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h3c); // write data only when single read is 0 assign sbdata0_reg_wren1 = (sb_state == RSP_RD) & sb_state_en & ~sbcs_sberror_wren; assign sbdata0_reg_wren = sbdata0_reg_wren0 | sbdata0_reg_wren1; assign sbdata1_reg_wren0 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h3d); // write data only when single read is 0; assign sbdata1_reg_wren1 = (sb_state == RSP_RD) & sb_state_en & ~sbcs_sberror_wren; assign sbdata1_reg_wren = sbdata1_reg_wren0 | sbdata1_reg_wren1; assign sbdata0_din[31:0] = ({32{sbdata0_reg_wren0}} & dmi_reg_wdata[31:0]) | ({32{sbdata0_reg_wren1}} & sb_bus_rdata[31:0]); assign sbdata1_din[31:0] = ({32{sbdata1_reg_wren0}} & dmi_reg_wdata[31:0]) | ({32{sbdata1_reg_wren1}} & sb_bus_rdata[63:32]); rvdffe #(32) dbg_sbdata0_reg (.*, .din(sbdata0_din[31:0]), .dout(sbdata0_reg[31:0]), .en(sbdata0_reg_wren), .rst_l(dbg_dm_rst_l)); rvdffe #(32) dbg_sbdata1_reg (.*, .din(sbdata1_din[31:0]), .dout(sbdata1_reg[31:0]), .en(sbdata1_reg_wren), .rst_l(dbg_dm_rst_l)); // sbaddress assign sbaddress0_reg_wren0 = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h39); assign sbaddress0_reg_wren = sbaddress0_reg_wren0 | sbaddress0_reg_wren1; assign sbaddress0_reg_din[31:0]= ({32{sbaddress0_reg_wren0}} & dmi_reg_wdata[31:0]) | ({32{sbaddress0_reg_wren1}} & (32'(sbaddress0_reg[31:0] + {28'b0,sbaddress0_incr[3:0]}))); rvdffe #(32) dbg_sbaddress0_reg (.*, .din(sbaddress0_reg_din[31:0]), .dout(sbaddress0_reg[31:0]), .en(sbaddress0_reg_wren), .rst_l(dbg_dm_rst_l)); assign sbreadonaddr_access = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h39) & sbcs_reg[20]; // if readonaddr is set the next command will start upon writing of addr0 assign sbreadondata_access = dmi_reg_en & ~dmi_reg_wr_en & (dmi_reg_addr == 7'h3c) & sbcs_reg[15]; // if readondata is set the next command will start upon reading of data0 assign sbdata0wr_access = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h3c); // write to sbdata0 will start write command to system bus // memory mapped registers // dmcontrol register has only 5 bits implemented. 31: haltreq, 30: resumereq, 28: ackhavereset, 1: ndmreset, 0: dmactive. // rest all the bits are zeroed out // dmactive flop is reset based on core rst_l, all other flops use dm_rst_l assign dmcontrol_wren = (dmi_reg_addr == 7'h10) & dmi_reg_en & dmi_reg_wr_en; assign dmcontrol_reg[29] = '0; assign dmcontrol_reg[27:2] = '0; assign resumereq = dmcontrol_reg[30] & ~dmcontrol_reg[31] & dmcontrol_wren_Q; rvdffs #(4) dmcontrolff (.din({dmi_reg_wdata[31:30],dmi_reg_wdata[28],dmi_reg_wdata[1]}), .dout({dmcontrol_reg[31:30], dmcontrol_reg[28], dmcontrol_reg[1]}), .en(dmcontrol_wren), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk)); rvdffs #(1) dmcontrol_dmactive_ff (.din(dmi_reg_wdata[0]), .dout(dmcontrol_reg[0]), .en(dmcontrol_wren), .rst_l(dbg_rst_l), .clk(dbg_free_clk)); rvdff #(1) dmcontrol_wrenff(.din(dmcontrol_wren), .dout(dmcontrol_wren_Q), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk)); // dmstatus register bits that are implemented // [19:18]-havereset,[17:16]-resume ack, [9:8]-halted, [3:0]-version // rest all the bits are zeroed out //assign dmstatus_wren = (dmi_reg_addr[31:0] == 32'h11) & dmi_reg_en; assign dmstatus_reg[31:20] = '0; assign dmstatus_reg[19:18] = {2{dmstatus_havereset}}; assign dmstatus_reg[15:14] = '0; assign dmstatus_reg[7] = '1; assign dmstatus_reg[6:4] = '0; assign dmstatus_reg[17:16] = {2{dmstatus_resumeack}}; assign dmstatus_reg[13:12] = {2{dmstatus_unavail}}; assign dmstatus_reg[11:10] = {2{dmstatus_running}}; assign dmstatus_reg[9:8] = {2{dmstatus_halted}}; assign dmstatus_reg[3:0] = 4'h2; assign dmstatus_resumeack_wren = ((dbg_state == RESUMING) & dec_tlu_resume_ack) | (dmstatus_resumeack & resumereq & dmstatus_halted); assign dmstatus_resumeack_din = (dbg_state == RESUMING) & dec_tlu_resume_ack; assign dmstatus_haveresetn_wren = (dmi_reg_addr == 7'h10) & dmi_reg_wdata[28] & dmi_reg_en & dmi_reg_wr_en & dmcontrol_reg[0]; // clear the havereset assign dmstatus_havereset = ~dmstatus_haveresetn; assign dmstatus_unavail = dmcontrol_reg[1] | ~rst_l_sync; assign dmstatus_running = ~(dmstatus_unavail | dmstatus_halted); rvdffs #(1) dmstatus_resumeack_reg (.din(dmstatus_resumeack_din), .dout(dmstatus_resumeack), .en(dmstatus_resumeack_wren), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk)); rvdff #(1) dmstatus_halted_reg (.din(dec_tlu_dbg_halted & ~dec_tlu_mpc_halted_only), .dout(dmstatus_halted), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk)); rvdffs #(1) dmstatus_haveresetn_reg (.din(1'b1), .dout(dmstatus_haveresetn), .en(dmstatus_haveresetn_wren), .rst_l(rst_l), .clk(dbg_free_clk)); // haltsum0 register assign haltsum0_reg[31:1] = '0; assign haltsum0_reg[0] = dmstatus_halted; // abstractcs register // bits implemted are [12] - busy and [10:8]= command error assign abstractcs_reg[31:13] = '0; assign abstractcs_reg[11] = '0; assign abstractcs_reg[7:4] = '0; assign abstractcs_reg[3:0] = 4'h2; // One data register assign abstractcs_error_sel0 = abstractcs_reg[12] & ~(|abstractcs_reg[10:8]) & dmi_reg_en & ((dmi_reg_wr_en & ((dmi_reg_addr == 7'h16) | (dmi_reg_addr == 7'h17)) | (dmi_reg_addr == 7'h18)) | (dmi_reg_addr == 7'h4) | (dmi_reg_addr == 7'h5)); assign abstractcs_error_sel1 = execute_command & ~(|abstractcs_reg[10:8]) & ((~((command_reg[31:24] == 8'b0) | (command_reg[31:24] == 8'h2))) | // Illegal command (((command_reg[22:20] == 3'b011) | (command_reg[22])) & (command_reg[31:24] == 8'h2)) | // Illegal abstract memory size (can't be DW or higher) ((command_reg[22:20] != 3'b010) & ((command_reg[31:24] == 8'h0) & command_reg[17])) | // Illegal abstract reg size ((command_reg[31:24] == 8'h0) & command_reg[18])); //postexec for abstract register access assign abstractcs_error_sel2 = ((core_dbg_cmd_done & core_dbg_cmd_fail) | // exception from core (execute_command & (command_reg[31:24] == 8'h0) & // unimplemented regs (((command_reg[15:12] == 4'h1) & (command_reg[11:5] != 0)) | (command_reg[15:13] != 0)))) & ~(|abstractcs_reg[10:8]); assign abstractcs_error_sel3 = execute_command & (dbg_state != HALTED) & ~(|abstractcs_reg[10:8]); assign abstractcs_error_sel4 = dbg_sb_bus_error & dbg_bus_clk_en & ~(|abstractcs_reg[10:8]);// sb bus error for abstract memory command assign abstractcs_error_sel5 = execute_command & (command_reg[31:24] == 8'h2) & ~(|abstractcs_reg[10:8]) & (((command_reg[22:20] == 3'b001) & data1_reg[0]) | ((command_reg[22:20] == 3'b010) & (|data1_reg[1:0]))); //Unaligned address for abstract memory assign abstractcs_error_sel6 = (dmi_reg_addr == 7'h16) & dmi_reg_en & dmi_reg_wr_en; assign abstractcs_error_din[2:0] = abstractcs_error_sel0 ? 3'b001 : // writing command or abstractcs while a command was executing. Or accessing data0 abstractcs_error_sel1 ? 3'b010 : // writing a illegal command type to cmd field of command abstractcs_error_sel2 ? 3'b011 : // exception while running command abstractcs_error_sel3 ? 3'b100 : // writing a comnand when not in the halted state abstractcs_error_sel4 ? 3'b101 : // Bus error abstractcs_error_sel5 ? 3'b111 : // unaligned or illegal size abstract memory command abstractcs_error_sel6 ? (~dmi_reg_wdata[10:8] & abstractcs_reg[10:8]) : //W1C abstractcs_reg[10:8]; //hold rvdffs #(1) dmabstractcs_busy_reg (.din(abstractcs_busy_din), .dout(abstractcs_reg[12]), .en(abstractcs_busy_wren), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk)); rvdff #(3) dmabstractcs_error_reg (.din(abstractcs_error_din[2:0]), .dout(abstractcs_reg[10:8]), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk)); // abstract auto reg assign abstractauto_reg_wren = dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h18) & ~abstractcs_reg[12]; rvdffs #(2) dbg_abstractauto_reg (.*, .din(dmi_reg_wdata[1:0]), .dout(abstractauto_reg[1:0]), .en(abstractauto_reg_wren), .rst_l(dbg_dm_rst_l), .clk(dbg_free_clk)); // command register - implemented all the bits in this register // command[16] = 1: write, 0: read assign execute_command_ns = command_wren | (dmi_reg_en & ~abstractcs_reg[12] & (((dmi_reg_addr == 7'h4) & abstractauto_reg[0]) | ((dmi_reg_addr == 7'h5) & abstractauto_reg[1]))); assign command_wren = (dmi_reg_addr == 7'h17) & dmi_reg_en & dmi_reg_wr_en; assign command_regno_wren = command_wren | ((command_reg[31:24] == 8'h0) & command_reg[19] & (dbg_state == CMD_DONE) & ~(|abstractcs_reg[10:8])); // aarpostincrement assign command_postexec_din = (dmi_reg_wdata[31:24] == 8'h0) & dmi_reg_wdata[18]; assign command_transfer_din = (dmi_reg_wdata[31:24] == 8'h0) & dmi_reg_wdata[17]; assign command_din[31:16] = {dmi_reg_wdata[31:24],1'b0,dmi_reg_wdata[22:19],command_postexec_din,command_transfer_din, dmi_reg_wdata[16]}; assign command_din[15:0] = command_wren ? dmi_reg_wdata[15:0] : dbg_cmd_next_addr[15:0]; rvdff #(1) execute_commandff (.*, .din(execute_command_ns), .dout(execute_command), .clk(dbg_free_clk), .rst_l(dbg_dm_rst_l)); rvdffe #(16) dmcommand_reg (.*, .din(command_din[31:16]), .dout(command_reg[31:16]), .en(command_wren), .rst_l(dbg_dm_rst_l)); rvdffe #(16) dmcommand_regno_reg (.*, .din(command_din[15:0]), .dout(command_reg[15:0]), .en(command_regno_wren), .rst_l(dbg_dm_rst_l)); // data0 reg assign data0_reg_wren0 = (dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h4) & (dbg_state == HALTED) & ~abstractcs_reg[12]); assign data0_reg_wren1 = core_dbg_cmd_done & (dbg_state == CORE_CMD_WAIT) & ~command_reg[16]; assign data0_reg_wren = data0_reg_wren0 | data0_reg_wren1 | data0_reg_wren2; assign data0_din[31:0] = ({32{data0_reg_wren0}} & dmi_reg_wdata[31:0]) | ({32{data0_reg_wren1}} & core_dbg_rddata[31:0]) | ({32{data0_reg_wren2}} & sb_bus_rdata[31:0]); rvdffe #(32) dbg_data0_reg (.*, .din(data0_din[31:0]), .dout(data0_reg[31:0]), .en(data0_reg_wren), .rst_l(dbg_dm_rst_l)); // data 1 assign data1_reg_wren0 = (dmi_reg_en & dmi_reg_wr_en & (dmi_reg_addr == 7'h5) & (dbg_state == HALTED) & ~abstractcs_reg[12]); assign data1_reg_wren1 = (dbg_state == CMD_DONE) & (command_reg[31:24] == 8'h2) & command_reg[19] & ~(|abstractcs_reg[10:8]); // aampostincrement assign data1_reg_wren = data1_reg_wren0 | data1_reg_wren1; assign data1_din[31:0] = ({32{data1_reg_wren0}} & dmi_reg_wdata[31:0]) | ({32{data1_reg_wren1}} & dbg_cmd_next_addr[31:0]); rvdffe #(32) dbg_data1_reg (.*, .din(data1_din[31:0]), .dout(data1_reg[31:0]), .en(data1_reg_wren), .rst_l(dbg_dm_rst_l)); rvdffs #(1) sb_abmem_cmd_doneff (.din(sb_abmem_cmd_done_in), .dout(sb_abmem_cmd_done), .en(sb_abmem_cmd_done_en), .clk(dbg_free_clk), .rst_l(dbg_dm_rst_l), .*); rvdffs #(1) sb_abmem_data_doneff (.din(sb_abmem_data_done_in), .dout(sb_abmem_data_done), .en(sb_abmem_data_done_en), .clk(dbg_free_clk), .rst_l(dbg_dm_rst_l), .*); // FSM to control the debug mode entry, command send/recieve, and Resume flow. always_comb begin dbg_nxtstate = IDLE; dbg_state_en = 1'b0; abstractcs_busy_wren = 1'b0; abstractcs_busy_din = 1'b0; dbg_halt_req = dmcontrol_wren_Q & dmcontrol_reg[31]; // single pulse output to the core. Need to drive every time this register is written since core might be halted due to MPC dbg_resume_req = 1'b0; // single pulse output to the core dbg_sb_bus_error = 1'b0; data0_reg_wren2 = 1'b0; sb_abmem_cmd_done_in = 1'b0; sb_abmem_data_done_in = 1'b0; sb_abmem_cmd_done_en = 1'b0; sb_abmem_data_done_en = 1'b0; case (dbg_state) IDLE: begin dbg_nxtstate = (dmstatus_reg[9] | dec_tlu_mpc_halted_only) ? HALTED : HALTING; // initiate the halt command to the core dbg_state_en = dmcontrol_reg[31] | dmstatus_reg[9] | dec_tlu_mpc_halted_only; // when the jtag writes the halt bit in the DM register, OR when the status indicates H dbg_halt_req = dmcontrol_reg[31]; // only when jtag has written the halt_req bit in the control. Removed debug mode qualification during MPC changes end HALTING : begin dbg_nxtstate = HALTED; // Goto HALTED once the core sends an ACK dbg_state_en = dmstatus_reg[9] | dec_tlu_mpc_halted_only; // core indicates halted end HALTED: begin // wait for halted to go away before send to resume. Else start of new command dbg_nxtstate = dmstatus_reg[9] ? (resumereq ? RESUMING : (((command_reg[31:24] == 8'h2) & abmem_addr_external) ? SB_CMD_START : CORE_CMD_START)) : (dmcontrol_reg[31] ? HALTING : IDLE); // This is MPC halted case dbg_state_en = (dmstatus_reg[9] & resumereq) | execute_command | ~(dmstatus_reg[9] | dec_tlu_mpc_halted_only); abstractcs_busy_wren = dbg_state_en & ((dbg_nxtstate == CORE_CMD_START) | (dbg_nxtstate == SB_CMD_START)); // write busy when a new command was written by jtag abstractcs_busy_din = 1'b1; dbg_resume_req = dbg_state_en & (dbg_nxtstate == RESUMING); // single cycle pulse to core if resuming end CORE_CMD_START: begin // Don't execute the command if cmderror or transfer=0 for abstract register access dbg_nxtstate = ((|abstractcs_reg[10:8]) | ((command_reg[31:24] == 8'h0) & ~command_reg[17])) ? CMD_DONE : CORE_CMD_WAIT; // new command sent to the core dbg_state_en = dbg_cmd_valid | (|abstractcs_reg[10:8]) | ((command_reg[31:24] == 8'h0) & ~command_reg[17]); end CORE_CMD_WAIT: begin dbg_nxtstate = CMD_DONE; dbg_state_en = core_dbg_cmd_done; // go to done state for one cycle after completing current command end SB_CMD_START: begin dbg_nxtstate = (|abstractcs_reg[10:8]) ? CMD_DONE : SB_CMD_SEND; dbg_state_en = (dbg_bus_clk_en & ~sb_cmd_pending) | (|abstractcs_reg[10:8]); end SB_CMD_SEND: begin sb_abmem_cmd_done_in = 1'b1; sb_abmem_data_done_in= 1'b1; sb_abmem_cmd_done_en = (sb_bus_cmd_read | sb_bus_cmd_write_addr) & dbg_bus_clk_en; sb_abmem_data_done_en= (sb_bus_cmd_read | sb_bus_cmd_write_data) & dbg_bus_clk_en; dbg_nxtstate = SB_CMD_RESP; dbg_state_en = (sb_abmem_cmd_done | sb_abmem_cmd_done_en) & (sb_abmem_data_done | sb_abmem_data_done_en) & dbg_bus_clk_en; end SB_CMD_RESP: begin dbg_nxtstate = CMD_DONE; dbg_state_en = (sb_bus_rsp_read | sb_bus_rsp_write) & dbg_bus_clk_en; dbg_sb_bus_error = (sb_bus_rsp_read | sb_bus_rsp_write) & sb_bus_rsp_error & dbg_bus_clk_en; data0_reg_wren2 = dbg_state_en & ~sb_abmem_cmd_write & ~dbg_sb_bus_error; end CMD_DONE: begin dbg_nxtstate = HALTED; dbg_state_en = 1'b1; abstractcs_busy_wren = dbg_state_en; // remove the busy bit from the abstracts ( bit 12 ) abstractcs_busy_din = 1'b0; sb_abmem_cmd_done_in = 1'b0; sb_abmem_data_done_in= 1'b0; sb_abmem_cmd_done_en = 1'b1; sb_abmem_data_done_en= 1'b1; end RESUMING : begin dbg_nxtstate = IDLE; dbg_state_en = dmstatus_reg[17]; // resume ack has been updated in the dmstatus register end /* All legal values are handled above. Exclude the default part from coverage. */ /*pragma coverage off*/ default : begin dbg_nxtstate = IDLE; dbg_state_en = 1'b0; abstractcs_busy_wren = 1'b0; abstractcs_busy_din = 1'b0; dbg_halt_req = 1'b0; // single pulse output to the core dbg_resume_req = 1'b0; // single pulse output to the core dbg_sb_bus_error = 1'b0; data0_reg_wren2 = 1'b0; sb_abmem_cmd_done_in = 1'b0; sb_abmem_data_done_in = 1'b0; sb_abmem_cmd_done_en = 1'b0; sb_abmem_data_done_en = 1'b0; end /*pragma coverage on*/ endcase end // always_comb begin assign dmi_reg_rdata_din[31:0] = ({32{dmi_reg_addr == 7'h4}} & data0_reg[31:0]) | ({32{dmi_reg_addr == 7'h5}} & data1_reg[31:0]) | ({32{dmi_reg_addr == 7'h10}} & {2'b0,dmcontrol_reg[29],1'b0,dmcontrol_reg[27:0]}) | // Read0 to Write only bits ({32{dmi_reg_addr == 7'h11}} & dmstatus_reg[31:0]) | ({32{dmi_reg_addr == 7'h16}} & abstractcs_reg[31:0]) | ({32{dmi_reg_addr == 7'h17}} & command_reg[31:0]) | ({32{dmi_reg_addr == 7'h18}} & {30'h0,abstractauto_reg[1:0]}) | ({32{dmi_reg_addr == 7'h40}} & haltsum0_reg[31:0]) | ({32{dmi_reg_addr == 7'h38}} & sbcs_reg[31:0]) | ({32{dmi_reg_addr == 7'h39}} & sbaddress0_reg[31:0]) | ({32{dmi_reg_addr == 7'h3c}} & sbdata0_reg[31:0]) | ({32{dmi_reg_addr == 7'h3d}} & sbdata1_reg[31:0]); rvdffs #($bits(state_t)) dbg_state_reg (.din(dbg_nxtstate), .dout({dbg_state}), .en(dbg_state_en), .rst_l(dbg_dm_rst_l & rst_l), .clk(dbg_free_clk)); rvdffe #(32) dmi_rddata_reg (.din(dmi_reg_rdata_din[31:0]), .dout(dmi_reg_rdata[31:0]), .en(dmi_reg_en), .rst_l(dbg_dm_rst_l), .clk(clk), .*); assign abmem_addr[31:0] = data1_reg[31:0]; assign abmem_addr_core_local = (abmem_addr_in_dccm_region | abmem_addr_in_iccm_region | abmem_addr_in_pic_region); assign abmem_addr_external = ~abmem_addr_core_local; assign abmem_addr_in_dccm_region = (abmem_addr[31:28] == pt.DCCM_REGION) & pt.DCCM_ENABLE; assign abmem_addr_in_iccm_region = (abmem_addr[31:28] == pt.ICCM_REGION) & pt.ICCM_ENABLE; assign abmem_addr_in_pic_region = (abmem_addr[31:28] == pt.PIC_REGION); // interface for the core assign dbg_cmd_addr[31:0] = (command_reg[31:24] == 8'h2) ? data1_reg[31:0] : {20'b0, command_reg[11:0]}; assign dbg_cmd_wrdata[31:0] = data0_reg[31:0]; assign dbg_cmd_valid = (dbg_state == CORE_CMD_START) & ~((|abstractcs_reg[10:8]) | ((command_reg[31:24] == 8'h0) & ~command_reg[17]) | ((command_reg[31:24] == 8'h2) & abmem_addr_external)) & dma_dbg_ready; assign dbg_cmd_write = command_reg[16]; assign dbg_cmd_type[1:0] = (command_reg[31:24] == 8'h2) ? 2'b10 : {1'b0, (command_reg[15:12] == 4'b0)}; assign dbg_cmd_size[1:0] = command_reg[21:20]; assign dbg_cmd_addr_incr[3:0] = (command_reg[31:24] == 8'h2) ? (4'h1 << sb_abmem_cmd_size[1:0]) : 4'h1; assign dbg_cmd_curr_addr[31:0] = (command_reg[31:24] == 8'h2) ? data1_reg[31:0] : {16'b0, command_reg[15:0]}; assign dbg_cmd_next_addr[31:0] = dbg_cmd_curr_addr[31:0] + {28'h0,dbg_cmd_addr_incr[3:0]}; // Ask DMA to stop taking bus trxns since debug request is done assign dbg_dma_bubble = ((dbg_state == CORE_CMD_START) & ~(|abstractcs_reg[10:8])) | (dbg_state == CORE_CMD_WAIT); assign sb_cmd_pending = (sb_state == CMD_RD) | (sb_state == CMD_WR) | (sb_state == CMD_WR_ADDR) | (sb_state == CMD_WR_DATA) | (sb_state == RSP_RD) | (sb_state == RSP_WR); assign sb_abmem_cmd_pending = (dbg_state == SB_CMD_START) | (dbg_state == SB_CMD_SEND) | (dbg_state== SB_CMD_RESP); // system bus FSM always_comb begin sb_nxtstate = SBIDLE; sb_state_en = 1'b0; sbcs_sbbusy_wren = 1'b0; sbcs_sbbusy_din = 1'b0; sbcs_sberror_wren = 1'b0; sbcs_sberror_din[2:0] = 3'b0; sbaddress0_reg_wren1 = 1'b0; case (sb_state) SBIDLE: begin sb_nxtstate = sbdata0wr_access ? WAIT_WR : WAIT_RD; sb_state_en = (sbdata0wr_access | sbreadondata_access | sbreadonaddr_access) & ~(|sbcs_reg[14:12]) & ~sbcs_reg[22]; sbcs_sbbusy_wren = sb_state_en; // set the single read bit if it is a singlread command sbcs_sbbusy_din = 1'b1; sbcs_sberror_wren = sbcs_wren & (|dmi_reg_wdata[14:12]); // write to clear the error bits sbcs_sberror_din[2:0] = ~dmi_reg_wdata[14:12] & sbcs_reg[14:12]; end WAIT_RD: begin sb_nxtstate = (sbcs_unaligned | sbcs_illegal_size) ? DONE : CMD_RD; sb_state_en = (dbg_bus_clk_en & ~sb_abmem_cmd_pending) | sbcs_unaligned | sbcs_illegal_size; sbcs_sberror_wren = sbcs_unaligned | sbcs_illegal_size; sbcs_sberror_din[2:0] = sbcs_unaligned ? 3'b011 : 3'b100; end WAIT_WR: begin sb_nxtstate = (sbcs_unaligned | sbcs_illegal_size) ? DONE : CMD_WR; sb_state_en = (dbg_bus_clk_en & ~sb_abmem_cmd_pending) | sbcs_unaligned | sbcs_illegal_size; sbcs_sberror_wren = sbcs_unaligned | sbcs_illegal_size; sbcs_sberror_din[2:0] = sbcs_unaligned ? 3'b011 : 3'b100; end CMD_RD : begin sb_nxtstate = RSP_RD; sb_state_en = sb_bus_cmd_read & dbg_bus_clk_en; end CMD_WR : begin sb_nxtstate = (sb_bus_cmd_write_addr & sb_bus_cmd_write_data) ? RSP_WR : (sb_bus_cmd_write_data ? CMD_WR_ADDR : CMD_WR_DATA); sb_state_en = (sb_bus_cmd_write_addr | sb_bus_cmd_write_data) & dbg_bus_clk_en; end CMD_WR_ADDR : begin sb_nxtstate = RSP_WR; sb_state_en = sb_bus_cmd_write_addr & dbg_bus_clk_en; end CMD_WR_DATA : begin sb_nxtstate = RSP_WR; sb_state_en = sb_bus_cmd_write_data & dbg_bus_clk_en; end RSP_RD: begin sb_nxtstate = DONE; sb_state_en = sb_bus_rsp_read & dbg_bus_clk_en; sbcs_sberror_wren = sb_state_en & sb_bus_rsp_error; sbcs_sberror_din[2:0] = 3'b010; end RSP_WR: begin sb_nxtstate = DONE; sb_state_en = sb_bus_rsp_write & dbg_bus_clk_en; sbcs_sberror_wren = sb_state_en & sb_bus_rsp_error; sbcs_sberror_din[2:0] = 3'b010; end DONE: begin sb_nxtstate = SBIDLE; sb_state_en = 1'b1; sbcs_sbbusy_wren = 1'b1; // reset the single read sbcs_sbbusy_din = 1'b0; sbaddress0_reg_wren1 = sbcs_reg[16] & (sbcs_reg[14:12] == 3'b0); // auto increment was set and no error. Update to new address after completing the current command end /* All legal values are handled above. Exclude the default part from coverage. */ /*pragma coverage off*/ default : begin sb_nxtstate = SBIDLE; sb_state_en = 1'b0; sbcs_sbbusy_wren = 1'b0; sbcs_sbbusy_din = 1'b0; sbcs_sberror_wren = 1'b0; sbcs_sberror_din[2:0] = 3'b0; sbaddress0_reg_wren1 = 1'b0; end /*pragma coverage on*/ endcase end // always_comb begin rvdffs #($bits(sb_state_t)) sb_state_reg (.din(sb_nxtstate), .dout({sb_state}), .en(sb_state_en), .rst_l(dbg_dm_rst_l), .clk(sb_free_clk)); assign sb_abmem_cmd_write = command_reg[16]; assign sb_abmem_cmd_size[2:0] = {1'b0, command_reg[21:20]}; assign sb_abmem_cmd_addr[31:0] = abmem_addr[31:0]; assign sb_abmem_cmd_wdata[31:0] = data0_reg[31:0]; assign sb_cmd_size[2:0] = sbcs_reg[19:17]; assign sb_cmd_wdata[63:0] = {sbdata1_reg[31:0], sbdata0_reg[31:0]}; assign sb_cmd_addr[31:0] = sbaddress0_reg[31:0]; assign sb_abmem_cmd_awvalid = (dbg_state == SB_CMD_SEND) & sb_abmem_cmd_write & ~sb_abmem_cmd_done; assign sb_abmem_cmd_wvalid = (dbg_state == SB_CMD_SEND) & sb_abmem_cmd_write & ~sb_abmem_data_done; assign sb_abmem_cmd_arvalid = (dbg_state == SB_CMD_SEND) & ~sb_abmem_cmd_write & ~sb_abmem_cmd_done & ~sb_abmem_data_done; assign sb_abmem_read_pend = (dbg_state == SB_CMD_RESP) & ~sb_abmem_cmd_write; assign sb_cmd_awvalid = ((sb_state == CMD_WR) | (sb_state == CMD_WR_ADDR)); assign sb_cmd_wvalid = ((sb_state == CMD_WR) | (sb_state == CMD_WR_DATA)); assign sb_cmd_arvalid = (sb_state == CMD_RD); assign sb_read_pend = (sb_state == RSP_RD); assign sb_axi_size[2:0] = (sb_abmem_cmd_awvalid | sb_abmem_cmd_wvalid | sb_abmem_cmd_arvalid | sb_abmem_read_pend) ? sb_abmem_cmd_size[2:0] : sb_cmd_size[2:0]; assign sb_axi_addr[31:0] = (sb_abmem_cmd_awvalid | sb_abmem_cmd_wvalid | sb_abmem_cmd_arvalid | sb_abmem_read_pend) ? sb_abmem_cmd_addr[31:0] : sb_cmd_addr[31:0]; assign sb_axi_wrdata[63:0] = (sb_abmem_cmd_awvalid | sb_abmem_cmd_wvalid) ? {2{sb_abmem_cmd_wdata[31:0]}} : sb_cmd_wdata[63:0]; // Generic bus response signals assign sb_bus_cmd_read = sb_axi_arvalid & sb_axi_arready; assign sb_bus_cmd_write_addr = sb_axi_awvalid & sb_axi_awready; assign sb_bus_cmd_write_data = sb_axi_wvalid & sb_axi_wready; assign sb_bus_rsp_read = sb_axi_rvalid & sb_axi_rready; assign sb_bus_rsp_write = sb_axi_bvalid & sb_axi_bready; assign sb_bus_rsp_error = (sb_bus_rsp_read & (|(sb_axi_rresp[1:0]))) | (sb_bus_rsp_write & (|(sb_axi_bresp[1:0]))); // AXI Request signals assign sb_axi_awvalid = sb_abmem_cmd_awvalid | sb_cmd_awvalid; assign sb_axi_awaddr[31:0] = sb_axi_addr[31:0]; assign sb_axi_awid[pt.SB_BUS_TAG-1:0] = '0; assign sb_axi_awsize[2:0] = sb_axi_size[2:0]; assign sb_axi_awprot[2:0] = 3'b001; assign sb_axi_awcache[3:0] = 4'b1111; assign sb_axi_awregion[3:0] = sb_axi_addr[31:28]; assign sb_axi_awlen[7:0] = '0; assign sb_axi_awburst[1:0] = 2'b01; assign sb_axi_awqos[3:0] = '0; assign sb_axi_awlock = '0; assign sb_axi_wvalid = sb_abmem_cmd_wvalid | sb_cmd_wvalid; assign sb_axi_wdata[63:0] = ({64{(sb_axi_size[2:0] == 3'h0)}} & {8{sb_axi_wrdata[7:0]}}) | ({64{(sb_axi_size[2:0] == 3'h1)}} & {4{sb_axi_wrdata[15:0]}}) | ({64{(sb_axi_size[2:0] == 3'h2)}} & {2{sb_axi_wrdata[31:0]}}) | ({64{(sb_axi_size[2:0] == 3'h3)}} & {sb_axi_wrdata[63:0]}); assign sb_axi_wstrb[7:0] = ({8{(sb_axi_size[2:0] == 3'h0)}} & (8'h1 << sb_axi_addr[2:0])) | ({8{(sb_axi_size[2:0] == 3'h1)}} & (8'h3 << {sb_axi_addr[2:1],1'b0})) | ({8{(sb_axi_size[2:0] == 3'h2)}} & (8'hf << {sb_axi_addr[2],2'b0})) | ({8{(sb_axi_size[2:0] == 3'h3)}} & 8'hff); assign sb_axi_wlast = '1; assign sb_axi_arvalid = sb_abmem_cmd_arvalid | sb_cmd_arvalid; assign sb_axi_araddr[31:0] = sb_axi_addr[31:0]; assign sb_axi_arid[pt.SB_BUS_TAG-1:0] = '0; assign sb_axi_arsize[2:0] = sb_axi_size[2:0]; assign sb_axi_arprot[2:0] = 3'b001; assign sb_axi_arcache[3:0] = 4'b0; assign sb_axi_arregion[3:0] = sb_axi_addr[31:28]; assign sb_axi_arlen[7:0] = '0; assign sb_axi_arburst[1:0] = 2'b01; assign sb_axi_arqos[3:0] = '0; assign sb_axi_arlock = '0; // AXI Response signals assign sb_axi_bready = 1'b1; assign sb_axi_rready = 1'b1; assign sb_bus_rdata[63:0] = ({64{sb_axi_size == 3'h0}} & ((sb_axi_rdata[63:0] >> 8*sb_axi_addr[2:0]) & 64'hff)) | ({64{sb_axi_size == 3'h1}} & ((sb_axi_rdata[63:0] >> 16*sb_axi_addr[2:1]) & 64'hffff)) | ({64{sb_axi_size == 3'h2}} & ((sb_axi_rdata[63:0] >> 32*sb_axi_addr[2]) & 64'hffff_ffff)) | ({64{sb_axi_size == 3'h3}} & sb_axi_rdata[63:0]); `ifdef RV_ASSERT_ON // assertion. // when the resume_ack is asserted then the dec_tlu_dbg_halted should be 0 dm_check_resume_and_halted: assert property (@(posedge clk) disable iff(~rst_l) (~dec_tlu_resume_ack | ~dec_tlu_dbg_halted)); assert_b2b_haltreq: assert property (@(posedge clk) disable iff (~(rst_l)) (##1 dbg_halt_req |=> ~dbg_halt_req)); // One cycle delay to fix weird issue around reset assert_halt_resume_onehot: assert #0 ($onehot0({dbg_halt_req, dbg_resume_req})); `endif endmodule ================================================ FILE: design/dec/cdecode ================================================ .definition # invalid rs2=0 c.add0 = [1001.....1....10] c.add1 = [1001......1...10] c.add2 = [1001.......1..10] c.add3 = [1001........1.10] c.add4 = [1001.........110] # invalid rs2=0 c.mv0 = [1000.....1....10] c.mv1 = [1000......1...10] c.mv2 = [1000.......1..10] c.mv3 = [1000........1.10] c.mv4 = [1000.........110] # invalid if rs1=0 c.jalr0 = [10011....0000010] c.jalr1 = [1001.1...0000010] c.jalr2 = [1001..1..0000010] c.jalr3 = [1001...1.0000010] c.jalr4 = [1001....10000010] c.addi = [000...........01] # invalid imm=0 c.addi16sp0 = [011100010.....01] c.addi16sp1 = [011.000101....01] c.addi16sp2 = [011.00010.1...01] c.addi16sp3 = [011.00010..1..01] c.addi16sp4 = [011.00010...1.01] c.addi16sp5 = [011.00010....101] # invalid uimm=0 c.addi4spn0 = [0001..........00] c.addi4spn1 = [000.1.........00] c.addi4spn2 = [000..1........00] c.addi4spn3 = [000...1.......00] c.addi4spn4 = [000....1......00] c.addi4spn5 = [000.....1.....00] c.addi4spn6 = [000......1....00] c.addi4spn7 = [000.......1...00] c.and = [100011...11...01] c.andi = [100.10........01] c.beqz = [110...........01] c.bnez = [111...........01] c.ebreak = [1001000000000010] c.j = [101...........01] c.jal = [001...........01] c.jr0 = [10001....0000010] c.jr1 = [1000.1...0000010] c.jr2 = [1000..1..0000010] c.jr3 = [1000...1.0000010] c.jr4 = [1000....10000010] c.li = [010...........01] # invalid rd=x2 or imm=0 c.lui0 = [01111.........01] c.lui1 = [0111.1........01] c.lui2 = [0111..1.......01] c.lui3 = [0111...0......01] c.lui4 = [0111....1.....01] c.lui5 = [011.1....1....01] c.lui6 = [011..1...1....01] c.lui7 = [011...1..1....01] c.lui8 = [011....0.1....01] c.lui9 = [011.....11....01] c.lui10= [011.1.....1...01] c.lui11= [011..1....1...01] c.lui12 = [011...1...1...01] c.lui13 = [011....0..1...01] c.lui14 = [011.....1.1...01] c.lui15 = [011.1......1..01] c.lui16 = [011..1.....1..01] c.lui17 = [011...1....1..01] c.lui18 = [011....0...1..01] c.lui19 = [011.....1..1..01] c.lui20 = [011.1.......1.01] c.lui21 = [011..1......1.01] c.lui22 = [011...1.....1.01] c.lui23 = [011....0....1.01] c.lui24 = [011.....1...1.01] c.lui25 = [011.1........101] c.lui26 = [011..1.......101] c.lui27 = [011...1......101] c.lui28 = [011....0.....101] c.lui29 = [011.....1....101] c.lw = [010...........00] # invalid if rd=x0 c.lwsp0 = [010.....1.....10] c.lwsp1 = [010....1......10] c.lwsp2 = [010...1.......10] c.lwsp3 = [010..1........10] c.lwsp4 = [010.1.........10] c.or = [100011...10...01] # bit 5 of the shift must be 0 to be legal c.slli = [0000..........10] c.srai = [100001........01] c.srli = [100000........01] c.sub = [100011...00...01] c.sw = [110...........00] c.swsp = [110...........10] c.xor = [100011...01...01] .input rv32c = { i[15] i[14] i[13] i[12] i[11] i[10] i[9] i[8] i[7] i[6] i[5] i[4] i[3] i[2] i[1] i[0] } .output rv32c = { rdrd rdrs1 rs2rs2 rdprd rdprs1 rs2prs2 rs2prd uimm9_2 ulwimm6_2 ulwspimm7_2 rdeq2 rdeq1 rs1eq2 sbroffset8_1 simm9_4 simm5_0 sjaloffset11_1 sluimm17_12 uimm5_0 uswimm6_2 uswspimm7_2 o[31] o[30] o[29] o[28] o[27] o[26] o[25] o[24] o[23] o[22] o[21] o[20] o[19] o[18] o[17] o[16] o[15] o[14] o[13] o[12] o[11] o[10] o[9] o[8] o[7] o[6] o[5] o[4] o[3] o[2] o[1] o[0] } # assign rs2d[4:0] = i[6:2]; # # assign rdd[4:0] = i[11:7]; # # assign rdpd[4:0] = {2'b01, i[9:7]}; # # assign rs2pd[4:0] = {2'b01, i[4:2]}; .decode rv32c[c.add{0-4}] = { rdrd rdrs1 rs2rs2 o[5] o[4] o[1] o[0] } rv32c[c.mv{0-4}] = { rdrd rs2rs2 o[5] o[4] o[1] o[0] } rv32c[c.addi] = { rdrd rdrs1 simm5_0 o[4] o[1] o[0] } rv32c[c.addi16sp{0-5}] = { rdeq2 rs1eq2 simm9_4 o[4] o[1] o[0] } rv32c[c.addi4spn{0-7}] = { rs2prd rs1eq2 uimm9_2 o[4] o[1] o[0] } rv32c[c.and] = { rdprd rdprs1 rs2prs2 o[14] o[13] o[12] o[5] o[4] o[1] o[0] } rv32c[c.andi] = { rdprd rdprs1 simm5_0 o[14] o[13] o[12] o[4] o[1] o[0] } rv32c[c.beqz] = { rdprs1 sbroffset8_1 o[6] o[5] o[1] o[0] } rv32c[c.bnez] = { rdprs1 sbroffset8_1 o[12] o[6] o[5] o[1] o[0] } rv32c[c.ebreak] = { o[20] o[6] o[5] o[4] o[1] o[0] } rv32c[c.j] = { sjaloffset11_1 o[6] o[5] o[3] o[2] o[1] o[0] } rv32c[c.jal] = { sjaloffset11_1 rdeq1 o[6] o[5] o[3] o[2] o[1] o[0] } rv32c[c.jalr{0-4}] = { rdeq1 rdrs1 o[6] o[5] o[2] o[1] o[0] } rv32c[c.jr{0-4}] = { rdrs1 o[6] o[5] o[2] o[1] o[0] } rv32c[c.li] = { rdrd simm5_0 o[4] o[1] o[0] } rv32c[c.lui{0-29}] = { rdrd sluimm17_12 o[5] o[4] o[2] o[1] o[0] } rv32c[c.lw] = { rs2prd rdprs1 ulwimm6_2 o[13] o[1] o[0] } rv32c[c.lwsp{0-4}] = { rdrd rs1eq2 ulwspimm7_2 o[13] o[1] o[0] } rv32c[c.or] = { rdprd rdprs1 rs2prs2 o[14] o[13] o[5] o[4] o[1] o[0] } rv32c[c.slli] = { rdrd rdrs1 uimm5_0 o[12] o[4] o[1] o[0] } rv32c[c.srai] = { rdprd rdprs1 uimm5_0 o[30] o[14] o[12] o[4] o[1] o[0] } rv32c[c.srli] = { rdprd rdprs1 uimm5_0 o[14] o[12] o[4] o[1] o[0] } rv32c[c.sub] = { rdprd rdprs1 rs2prs2 o[30] o[5] o[4] o[1] o[0] } rv32c[c.sw] = { rdprs1 rs2prs2 uswimm6_2 o[13] o[5] o[1] o[0] } rv32c[c.swsp] = { rs2rs2 rs1eq2 uswspimm7_2 o[13] o[5] o[1] o[0] } rv32c[c.xor] = { rdprd rdprs1 rs2prs2 o[14] o[5] o[4] o[1] o[0] } .end ================================================ FILE: design/dec/csrdecode_m ================================================ .definition csr_misa = [001100000001] csr_mvendorid = [111100010001] csr_marchid = [111100010010] csr_mimpid = [111100010011] csr_mhartid = [111100010100] csr_mstatus = [001100000000] csr_mtvec = [001100000101] csr_mip = [001101000100] csr_mie = [001100000100] csr_mcyclel = [101100000000] csr_mcycleh = [101110000000] csr_minstretl = [101100000010] csr_minstreth = [101110000010] csr_mscratch = [001101000000] csr_mepc = [001101000001] csr_mcause = [001101000010] csr_mscause = [011111111111] csr_mtval = [001101000011] csr_mrac = [011111000000] csr_dmst = [011111000100] csr_mdeau = [101111000000] csr_mdseac = [111111000000] csr_meivt = [101111001000] csr_meihap = [111111001000] csr_meipt = [101111001001] csr_meicpct = [101111001010] csr_meicurpl = [101111001100] csr_meicidpl = [101111001011] csr_dcsr = [011110110000] csr_dpc = [011110110001] csr_dicawics = [011111001000] csr_dicad0h = [011111001100] csr_dicad0 = [011111001001] csr_dicad1 = [011111001010] csr_dicago = [011111001011] csr_mtsel = [011110100000] csr_mtdata1 = [011110100001] csr_mtdata2 = [011110100010] csr_mhpmc3 = [101100000011] csr_mhpmc4 = [101100000100] csr_mhpmc5 = [101100000101] csr_mhpmc6 = [101100000110] csr_mhpmc3h = [101110000011] csr_mhpmc4h = [101110000100] csr_mhpmc5h = [101110000101] csr_mhpmc6h = [101110000110] csr_mhpme3 = [001100100011] csr_mhpme4 = [001100100100] csr_mhpme5 = [001100100101] csr_mhpme6 = [001100100110] csr_micect = [011111110000] csr_miccmect = [011111110001] csr_mdccmect = [011111110010] csr_mpmc = [011111000110] csr_mcgc = [011111111000] csr_mcpc = [011111000010] csr_mfdc = [011111111001] csr_mitctl0 = [011111010100] csr_mitctl1 = [011111010111] csr_mitb0 = [011111010011] csr_mitb1 = [011111010110] csr_mitcnt0 = [011111010010] csr_mitcnt1 = [011111010101] csr_perfva = [101100000111] csr_perfvb = [101100001...] csr_perfvc = [10110001....] csr_perfvd = [101110000111] csr_perfve = [101110001...] csr_perfvf = [10111001....] csr_perfvg = [001100100111] csr_perfvh = [001100101...] csr_perfvi = [00110011....] csr_mcountinhibit = [001100100000] csr_mfdht = [011111001110] csr_mfdhs = [011111001111] csr_pmpcfg = [00111010....] csr_pmpaddr0 = [00111011....] csr_pmpaddr16 = [00111100....] csr_pmpaddr32 = [00111101....] csr_pmpaddr48 = [00111110....] .input csr = { dec_csr_rdaddr_d[11] dec_csr_rdaddr_d[10] dec_csr_rdaddr_d[9] dec_csr_rdaddr_d[8] dec_csr_rdaddr_d[7] dec_csr_rdaddr_d[6] dec_csr_rdaddr_d[5] dec_csr_rdaddr_d[4] dec_csr_rdaddr_d[3] dec_csr_rdaddr_d[2] dec_csr_rdaddr_d[1] dec_csr_rdaddr_d[0] } .output csr = { csr_misa csr_mvendorid csr_marchid csr_mimpid csr_mhartid csr_mstatus csr_mtvec csr_mip csr_mie csr_mcyclel csr_mcycleh csr_minstretl csr_minstreth csr_mscratch csr_mepc csr_mcause csr_mscause csr_mtval csr_mrac csr_dmst csr_mdseac csr_meihap csr_meivt csr_meipt csr_meicurpl csr_meicidpl csr_dcsr csr_mcgc csr_mfdc csr_dpc csr_mtsel csr_mtdata1 csr_mtdata2 csr_mhpmc3 csr_mhpmc4 csr_mhpmc5 csr_mhpmc6 csr_mhpmc3h csr_mhpmc4h csr_mhpmc5h csr_mhpmc6h csr_mhpme3 csr_mhpme4 csr_mhpme5 csr_mhpme6 csr_mcountinhibit csr_mitctl0 csr_mitctl1 csr_mitb0 csr_mitb1 csr_mitcnt0 csr_mitcnt1 csr_perfva csr_perfvb csr_perfvc csr_perfvd csr_perfve csr_perfvf csr_perfvg csr_perfvh csr_perfvi csr_mpmc csr_mcpc csr_meicpct csr_mdeau csr_micect csr_miccmect csr_mdccmect csr_mfdht csr_mfdhs csr_dicawics csr_dicad0h csr_dicad0 csr_dicad1 csr_dicago csr_pmpcfg csr_pmpaddr0 csr_pmpaddr16 csr_pmpaddr32 csr_pmpaddr48 valid_only presync postsync } .decode csr[ csr_misa ] = { csr_misa } csr[ csr_mvendorid ] = { csr_mvendorid } csr[ csr_marchid ] = { csr_marchid } csr[ csr_mimpid ] = { csr_mimpid } csr[ csr_mhartid ] = { csr_mhartid } csr[ csr_mstatus ] = { csr_mstatus postsync } csr[ csr_mtvec ] = { csr_mtvec postsync} csr[ csr_mip ] = { csr_mip } csr[ csr_mie ] = { csr_mie } csr[ csr_mcyclel ] = { csr_mcyclel } csr[ csr_mcycleh ] = { csr_mcycleh } csr[ csr_minstretl ] = { csr_minstretl presync } csr[ csr_minstreth ] = { csr_minstreth presync } csr[ csr_mscratch ] = { csr_mscratch } csr[ csr_mepc ] = { csr_mepc postsync} csr[ csr_mcause ] = { csr_mcause } csr[ csr_mscause ] = { csr_mscause } csr[ csr_mtval ] = { csr_mtval } csr[ csr_mrac ] = { csr_mrac postsync } csr[ csr_dmst ] = { csr_dmst postsync} csr[ csr_mdseac ] = { csr_mdseac } csr[ csr_meipt ] = { csr_meipt } csr[ csr_meihap ] = { csr_meihap } csr[ csr_meivt ] = { csr_meivt } csr[ csr_meicurpl ] = { csr_meicurpl } csr[ csr_mdeau ] = { csr_mdeau } csr[ csr_meicpct ] = { csr_meicpct } csr[ csr_mpmc ] = { csr_mpmc } csr[ csr_mcpc ] = { csr_mcpc presync postsync } csr[ csr_meicidpl ] = { csr_meicidpl } csr[ csr_mcgc ] = { csr_mcgc } csr[ csr_mcountinhibit] = { csr_mcountinhibit presync postsync } csr[ csr_mfdc ] = { csr_mfdc presync postsync } csr[ csr_dcsr ] = { csr_dcsr } csr[ csr_dpc ] = { csr_dpc } csr[ csr_mtsel ] = { csr_mtsel } csr[ csr_mtdata1 ] = { csr_mtdata1 presync postsync } csr[ csr_mtdata2 ] = { csr_mtdata2 postsync } csr[ csr_mhpmc3 ] = { csr_mhpmc3 presync } csr[ csr_mhpmc4 ] = { csr_mhpmc4 presync } csr[ csr_mhpmc5 ] = { csr_mhpmc5 presync } csr[ csr_mhpmc6 ] = { csr_mhpmc6 presync } csr[ csr_mhpmc3h ] = { csr_mhpmc3h presync } csr[ csr_mhpmc4h ] = { csr_mhpmc4h presync } csr[ csr_mhpmc5h ] = { csr_mhpmc5h presync } csr[ csr_mhpmc6h ] = { csr_mhpmc6h presync } csr[ csr_mhpme3 ] = { csr_mhpme3 } csr[ csr_mhpme4 ] = { csr_mhpme4 } csr[ csr_mhpme5 ] = { csr_mhpme5 } csr[ csr_mhpme6 ] = { csr_mhpme6 } csr[ csr_micect ] = { csr_micect } csr[ csr_miccmect ] = { csr_miccmect } csr[ csr_mdccmect ] = { csr_mdccmect } csr[ csr_dicawics ] = { csr_dicawics } csr[ csr_dicad0h ] = { csr_dicad0h } csr[ csr_dicad0 ] = { csr_dicad0 } csr[ csr_dicad1 ] = { csr_dicad1 } csr[ csr_dicago ] = { csr_dicago } csr[ csr_mitctl0 ] = { csr_mitctl0 } csr[ csr_mitctl1 ] = { csr_mitctl1 } csr[ csr_mitb0 ] = { csr_mitb0 } csr[ csr_mitb1 ] = { csr_mitb1 } csr[ csr_mitcnt0 ] = { csr_mitcnt0 } csr[ csr_mitcnt1 ] = { csr_mitcnt1 } csr[ csr_mfdht ] = { csr_mfdht } csr[ csr_mfdhs ] = { csr_mfdhs } csr[ csr_mcountinhibit] = { csr_mcountinhibit presync postsync } csr[ csr_perfva ] = { valid_only } csr[ csr_perfvb ] = { valid_only } csr[ csr_perfvc ] = { valid_only } csr[ csr_perfvd ] = { valid_only } csr[ csr_perfve ] = { valid_only } csr[ csr_perfvf ] = { valid_only } csr[ csr_perfvg ] = { valid_only } csr[ csr_perfvh ] = { valid_only } csr[ csr_perfvi ] = { valid_only } csr[ csr_pmpcfg ] = { csr_pmpcfg } csr[ csr_pmpaddr0 ] = { csr_pmpaddr0 } csr[ csr_pmpaddr16 ] = { csr_pmpaddr16 } csr[ csr_pmpaddr32 ] = { csr_pmpaddr32 } csr[ csr_pmpaddr48 ] = { csr_pmpaddr48 } .end ================================================ FILE: design/dec/csrdecode_mu ================================================ .definition csr_misa = [001100000001] csr_mvendorid = [111100010001] csr_marchid = [111100010010] csr_mimpid = [111100010011] csr_mhartid = [111100010100] csr_mstatus = [001100000000] csr_mtvec = [001100000101] csr_mip = [001101000100] csr_mie = [001100000100] csr_mcyclel = [101100000000] csr_mcycleh = [101110000000] csr_minstretl = [101100000010] csr_minstreth = [101110000010] csr_mscratch = [001101000000] csr_mepc = [001101000001] csr_mcause = [001101000010] csr_mscause = [011111111111] csr_mtval = [001101000011] csr_mrac = [011111000000] csr_dmst = [011111000100] csr_mdeau = [101111000000] csr_mdseac = [111111000000] csr_meivt = [101111001000] csr_meihap = [111111001000] csr_meipt = [101111001001] csr_meicpct = [101111001010] csr_meicurpl = [101111001100] csr_meicidpl = [101111001011] csr_dcsr = [011110110000] csr_dpc = [011110110001] csr_dicawics = [011111001000] csr_dicad0h = [011111001100] csr_dicad0 = [011111001001] csr_dicad1 = [011111001010] csr_dicago = [011111001011] csr_mtsel = [011110100000] csr_mtdata1 = [011110100001] csr_mtdata2 = [011110100010] csr_mhpmc3 = [101100000011] csr_mhpmc4 = [101100000100] csr_mhpmc5 = [101100000101] csr_mhpmc6 = [101100000110] csr_mhpmc3h = [101110000011] csr_mhpmc4h = [101110000100] csr_mhpmc5h = [101110000101] csr_mhpmc6h = [101110000110] csr_mhpme3 = [001100100011] csr_mhpme4 = [001100100100] csr_mhpme5 = [001100100101] csr_mhpme6 = [001100100110] csr_micect = [011111110000] csr_miccmect = [011111110001] csr_mdccmect = [011111110010] csr_mpmc = [011111000110] csr_mcgc = [011111111000] csr_mcpc = [011111000010] csr_mfdc = [011111111001] csr_mitctl0 = [011111010100] csr_mitctl1 = [011111010111] csr_mitb0 = [011111010011] csr_mitb1 = [011111010110] csr_mitcnt0 = [011111010010] csr_mitcnt1 = [011111010101] csr_perfva = [101100000111] csr_perfvb = [101100001...] csr_perfvc = [10110001....] csr_perfvd = [101110000111] csr_perfve = [101110001...] csr_perfvf = [10111001....] csr_perfvg = [001100100111] csr_perfvh = [001100101...] csr_perfvi = [00110011....] csr_mcounteren = [001100000110] csr_mcountinhibit = [001100100000] csr_mfdht = [011111001110] csr_mfdhs = [011111001111] csr_menvcfg = [001100001010] csr_menvcfgh = [001100011010] csr_pmpcfg = [00111010....] csr_pmpaddr0 = [00111011....] csr_pmpaddr16 = [00111100....] csr_pmpaddr32 = [00111101....] csr_pmpaddr48 = [00111110....] csr_cyclel = [110000000000] csr_cycleh = [110010000000] csr_instretl = [110000000010] csr_instreth = [110010000010] csr_hpmc3 = [110000000011] csr_hpmc4 = [110000000100] csr_hpmc5 = [110000000101] csr_hpmc6 = [110000000110] csr_hpmc3h = [110010000011] csr_hpmc4h = [110010000100] csr_hpmc5h = [110010000101] csr_hpmc6h = [110010000110] csr_mseccfgl = [011101000111] csr_mseccfgh = [011101010111] .input csr = { dec_csr_rdaddr_d[11] dec_csr_rdaddr_d[10] dec_csr_rdaddr_d[9] dec_csr_rdaddr_d[8] dec_csr_rdaddr_d[7] dec_csr_rdaddr_d[6] dec_csr_rdaddr_d[5] dec_csr_rdaddr_d[4] dec_csr_rdaddr_d[3] dec_csr_rdaddr_d[2] dec_csr_rdaddr_d[1] dec_csr_rdaddr_d[0] } .output csr = { csr_misa csr_mvendorid csr_marchid csr_mimpid csr_mhartid csr_mstatus csr_mtvec csr_mip csr_mie csr_mcyclel csr_mcycleh csr_minstretl csr_minstreth csr_mscratch csr_mepc csr_mcause csr_mscause csr_mtval csr_mrac csr_dmst csr_mdseac csr_meihap csr_meivt csr_meipt csr_meicurpl csr_meicidpl csr_dcsr csr_mcgc csr_mfdc csr_dpc csr_mtsel csr_mtdata1 csr_mtdata2 csr_mhpmc3 csr_mhpmc4 csr_mhpmc5 csr_mhpmc6 csr_mhpmc3h csr_mhpmc4h csr_mhpmc5h csr_mhpmc6h csr_mhpme3 csr_mhpme4 csr_mhpme5 csr_mhpme6 csr_mcounteren csr_mcountinhibit csr_mitctl0 csr_mitctl1 csr_mitb0 csr_mitb1 csr_mitcnt0 csr_mitcnt1 csr_perfva csr_perfvb csr_perfvc csr_perfvd csr_perfve csr_perfvf csr_perfvg csr_perfvh csr_perfvi csr_mpmc csr_mcpc csr_meicpct csr_mdeau csr_micect csr_miccmect csr_mdccmect csr_mfdht csr_mfdhs csr_dicawics csr_dicad0h csr_dicad0 csr_dicad1 csr_dicago csr_menvcfg csr_menvcfgh csr_pmpcfg csr_pmpaddr0 csr_pmpaddr16 csr_pmpaddr32 csr_pmpaddr48 csr_cyclel csr_cycleh csr_instretl csr_instreth csr_hpmc3 csr_hpmc4 csr_hpmc5 csr_hpmc6 csr_hpmc3h csr_hpmc4h csr_hpmc5h csr_hpmc6h csr_mseccfgl csr_mseccfgh valid_only presync postsync } .decode csr[ csr_misa ] = { csr_misa } csr[ csr_mvendorid ] = { csr_mvendorid } csr[ csr_marchid ] = { csr_marchid } csr[ csr_mimpid ] = { csr_mimpid } csr[ csr_mhartid ] = { csr_mhartid } csr[ csr_mstatus ] = { csr_mstatus postsync } csr[ csr_mtvec ] = { csr_mtvec postsync} csr[ csr_mip ] = { csr_mip } csr[ csr_mie ] = { csr_mie } csr[ csr_mcyclel ] = { csr_mcyclel } csr[ csr_mcycleh ] = { csr_mcycleh } csr[ csr_minstretl ] = { csr_minstretl presync } csr[ csr_minstreth ] = { csr_minstreth presync } csr[ csr_mscratch ] = { csr_mscratch } csr[ csr_mepc ] = { csr_mepc postsync} csr[ csr_mcause ] = { csr_mcause } csr[ csr_mscause ] = { csr_mscause } csr[ csr_mtval ] = { csr_mtval } csr[ csr_mrac ] = { csr_mrac postsync } csr[ csr_dmst ] = { csr_dmst postsync} csr[ csr_mdseac ] = { csr_mdseac } csr[ csr_meipt ] = { csr_meipt } csr[ csr_meihap ] = { csr_meihap } csr[ csr_meivt ] = { csr_meivt } csr[ csr_meicurpl ] = { csr_meicurpl } csr[ csr_mdeau ] = { csr_mdeau } csr[ csr_meicpct ] = { csr_meicpct } csr[ csr_mpmc ] = { csr_mpmc } csr[ csr_mcpc ] = { csr_mcpc presync postsync } csr[ csr_meicidpl ] = { csr_meicidpl } csr[ csr_mcgc ] = { csr_mcgc } csr[ csr_mcountinhibit] = { csr_mcountinhibit presync postsync } csr[ csr_mfdc ] = { csr_mfdc presync postsync } csr[ csr_dcsr ] = { csr_dcsr } csr[ csr_dpc ] = { csr_dpc } csr[ csr_mtsel ] = { csr_mtsel } csr[ csr_mtdata1 ] = { csr_mtdata1 presync postsync } csr[ csr_mtdata2 ] = { csr_mtdata2 postsync } csr[ csr_mhpmc3 ] = { csr_mhpmc3 presync } csr[ csr_mhpmc4 ] = { csr_mhpmc4 presync } csr[ csr_mhpmc5 ] = { csr_mhpmc5 presync } csr[ csr_mhpmc6 ] = { csr_mhpmc6 presync } csr[ csr_mhpmc3h ] = { csr_mhpmc3h presync } csr[ csr_mhpmc4h ] = { csr_mhpmc4h presync } csr[ csr_mhpmc5h ] = { csr_mhpmc5h presync } csr[ csr_mhpmc6h ] = { csr_mhpmc6h presync } csr[ csr_mhpme3 ] = { csr_mhpme3 } csr[ csr_mhpme4 ] = { csr_mhpme4 } csr[ csr_mhpme5 ] = { csr_mhpme5 } csr[ csr_mhpme6 ] = { csr_mhpme6 } csr[ csr_micect ] = { csr_micect } csr[ csr_miccmect ] = { csr_miccmect } csr[ csr_mdccmect ] = { csr_mdccmect } csr[ csr_dicawics ] = { csr_dicawics } csr[ csr_dicad0h ] = { csr_dicad0h } csr[ csr_dicad0 ] = { csr_dicad0 } csr[ csr_dicad1 ] = { csr_dicad1 } csr[ csr_dicago ] = { csr_dicago } csr[ csr_mitctl0 ] = { csr_mitctl0 } csr[ csr_mitctl1 ] = { csr_mitctl1 } csr[ csr_mitb0 ] = { csr_mitb0 } csr[ csr_mitb1 ] = { csr_mitb1 } csr[ csr_mitcnt0 ] = { csr_mitcnt0 } csr[ csr_mitcnt1 ] = { csr_mitcnt1 } csr[ csr_mfdht ] = { csr_mfdht } csr[ csr_mfdhs ] = { csr_mfdhs } csr[ csr_menvcfg ] = { csr_menvcfg } csr[ csr_menvcfgh ] = { csr_menvcfgh } csr[ csr_mcounteren ] = { csr_mcounteren } csr[ csr_mcountinhibit] = { csr_mcountinhibit presync postsync } csr[ csr_perfva ] = { valid_only } csr[ csr_perfvb ] = { valid_only } csr[ csr_perfvc ] = { valid_only } csr[ csr_perfvd ] = { valid_only } csr[ csr_perfve ] = { valid_only } csr[ csr_perfvf ] = { valid_only } csr[ csr_perfvg ] = { valid_only } csr[ csr_perfvh ] = { valid_only } csr[ csr_perfvi ] = { valid_only } csr[ csr_pmpcfg ] = { csr_pmpcfg } csr[ csr_pmpaddr0 ] = { csr_pmpaddr0 } csr[ csr_pmpaddr16 ] = { csr_pmpaddr16 } csr[ csr_pmpaddr32 ] = { csr_pmpaddr32 } csr[ csr_pmpaddr48 ] = { csr_pmpaddr48 } csr[ csr_cyclel ] = { csr_cyclel } csr[ csr_cycleh ] = { csr_cycleh } csr[ csr_instretl ] = { csr_instretl presync } csr[ csr_instreth ] = { csr_instreth presync } csr[ csr_hpmc3 ] = { csr_hpmc3 presync } csr[ csr_hpmc4 ] = { csr_hpmc4 presync } csr[ csr_hpmc5 ] = { csr_hpmc5 presync } csr[ csr_hpmc6 ] = { csr_hpmc6 presync } csr[ csr_hpmc3h ] = { csr_hpmc3h presync } csr[ csr_hpmc4h ] = { csr_hpmc4h presync } csr[ csr_hpmc5h ] = { csr_hpmc5h presync } csr[ csr_hpmc6h ] = { csr_hpmc6h presync } csr[ csr_mseccfgl ] = { csr_mseccfgl } csr[ csr_mseccfgh ] = { csr_mseccfgh } .end ================================================ FILE: design/dec/decode ================================================ .definition clz = [011000000000.....001.....0010011] ctz = [011000000001.....001.....0010011] cpop = [011000000010.....001.....0010011] sext_b = [011000000100.....001.....0010011] sext_h = [011000000101.....001.....0010011] min = [0000101..........100.....0110011] max = [0000101..........110.....0110011] minu = [0000101..........101.....0110011] maxu = [0000101..........111.....0110011] andn = [0100000..........111.....0110011] orn = [0100000..........110.....0110011] xnor = [0100000..........100.....0110011] #pack = [0000100..........100.....0110011] zext_h = [000010000000.....100.....0110011] pack1 = [000010000001.....100.....0110011] pack2 = [000010000010.....100.....0110011] pack3 = [000010000011.....100.....0110011] pack4 = [000010000100.....100.....0110011] pack5 = [000010000101.....100.....0110011] pack6 = [000010000110.....100.....0110011] pack7 = [000010000111.....100.....0110011] pack8 = [000010001000.....100.....0110011] pack9 = [000010001001.....100.....0110011] pack10 = [000010001010.....100.....0110011] pack11 = [000010001011.....100.....0110011] pack12 = [000010001100.....100.....0110011] pack13 = [000010001101.....100.....0110011] pack14 = [000010001110.....100.....0110011] pack15 = [000010001111.....100.....0110011] pack16 = [000010010000.....100.....0110011] pack17 = [000010010001.....100.....0110011] pack18 = [000010010010.....100.....0110011] pack19 = [000010010011.....100.....0110011] pack20 = [000010010100.....100.....0110011] pack21 = [000010010101.....100.....0110011] pack22 = [000010010110.....100.....0110011] pack23 = [000010010111.....100.....0110011] pack24 = [000010011000.....100.....0110011] pack25 = [000010011001.....100.....0110011] pack26 = [000010011010.....100.....0110011] pack27 = [000010011011.....100.....0110011] pack28 = [000010011100.....100.....0110011] pack29 = [000010011101.....100.....0110011] pack30 = [000010011110.....100.....0110011] pack31 = [000010011111.....100.....0110011] packu = [0100100..........100.....0110011] packh = [0000100..........111.....0110011] rol = [0110000..........001.....0110011] ror = [0110000..........101.....0110011] rori = [0110000..........101.....0010011] sh1add = [0010000..........010.....0110011] sh2add = [0010000..........100.....0110011] sh3add = [0010000..........110.....0110011] bset = [0010100..........001.....0110011] bclr = [0100100..........001.....0110011] binv = [0110100..........001.....0110011] bext = [0100100..........101.....0110011] bseti = [0010100..........001.....0010011] bclri = [0100100..........001.....0010011] binvi = [0110100..........001.....0010011] bexti = [0100100..........101.....0010011] grev = [0110100..........101.....0110011] #grevi = [01101............101.....0010011] grevi0 = [011010000000.....101.....0010011] grevi1 = [011010000001.....101.....0010011] grevi2 = [011010000010.....101.....0010011] grevi3 = [011010000011.....101.....0010011] grevi4 = [011010000100.....101.....0010011] grevi5 = [011010000101.....101.....0010011] grevi6 = [011010000110.....101.....0010011] grevi7 = [011010000111.....101.....0010011] grevi8 = [011010001000.....101.....0010011] grevi9 = [011010001001.....101.....0010011] grevi10 = [011010001010.....101.....0010011] grevi11 = [011010001011.....101.....0010011] grevi12 = [011010001100.....101.....0010011] grevi13 = [011010001101.....101.....0010011] grevi14 = [011010001110.....101.....0010011] grevi15 = [011010001111.....101.....0010011] grevi16 = [011010010000.....101.....0010011] grevi17 = [011010010001.....101.....0010011] grevi18 = [011010010010.....101.....0010011] grevi19 = [011010010011.....101.....0010011] grevi20 = [011010010100.....101.....0010011] grevi21 = [011010010101.....101.....0010011] grevi22 = [011010010110.....101.....0010011] grevi23 = [011010010111.....101.....0010011] #grevi24 = [011010011000.....101.....0010011] # REV8 rev8 = [011010011000.....101.....0010011] grevi25 = [011010011001.....101.....0010011] grevi26 = [011010011010.....101.....0010011] grevi27 = [011010011011.....101.....0010011] grevi28 = [011010011100.....101.....0010011] grevi29 = [011010011101.....101.....0010011] grevi30 = [011010011110.....101.....0010011] grevi31 = [011010011111.....101.....0010011] gorc = [0010100..........101.....0110011] #gorci = [00101............101.....0010011] gorci0 = [001010000000.....101.....0010011] gorci1 = [001010000001.....101.....0010011] gorci2 = [001010000010.....101.....0010011] gorci3 = [001010000011.....101.....0010011] gorci4 = [001010000100.....101.....0010011] gorci5 = [001010000101.....101.....0010011] gorci6 = [001010000110.....101.....0010011] #gorci7 = [001010000111.....101.....0010011] # ORC_B orc_b = [001010000111.....101.....0010011] gorci8 = [001010001000.....101.....0010011] gorci9 = [001010001001.....101.....0010011] gorci10 = [001010001010.....101.....0010011] gorci11 = [001010001011.....101.....0010011] gorci12 = [001010001100.....101.....0010011] gorci13 = [001010001101.....101.....0010011] gorci14 = [001010001110.....101.....0010011] gorci15 = [001010001111.....101.....0010011] gorci16 = [001010010000.....101.....0010011] gorci17 = [001010010001.....101.....0010011] gorci18 = [001010010010.....101.....0010011] gorci19 = [001010010011.....101.....0010011] gorci20 = [001010010100.....101.....0010011] gorci21 = [001010010101.....101.....0010011] gorci22 = [001010010110.....101.....0010011] gorci23 = [001010010111.....101.....0010011] gorci24 = [001010011000.....101.....0010011] gorci25 = [001010011001.....101.....0010011] gorci26 = [001010011010.....101.....0010011] gorci27 = [001010011011.....101.....0010011] gorci28 = [001010011100.....101.....0010011] gorci29 = [001010011101.....101.....0010011] gorci30 = [001010011110.....101.....0010011] gorci31 = [001010011111.....101.....0010011] shfl = [0000100..........001.....0110011] shfli = [00001000.........001.....0010011] unshfl = [0000100..........101.....0110011] unshfli = [00001000.........101.....0010011] bdecompress = [0100100..........110.....0110011] bcompress = [0000100..........110.....0110011] clmul = [0000101..........001.....0110011] clmulr = [0000101..........010.....0110011] clmulh = [0000101..........011.....0110011] crc32_b = [011000010000.....001.....0010011] crc32_h = [011000010001.....001.....0010011] crc32_w = [011000010010.....001.....0010011] crc32c_b = [011000011000.....001.....0010011] crc32c_h = [011000011001.....001.....0010011] crc32c_w = [011000011010.....001.....0010011] bfp = [0100100..........111.....0110011] xperm_n = [0010100..........010.....0110011] xperm_b = [0010100..........100.....0110011] xperm_h = [0010100..........110.....0110011] add = [0000000..........000.....0110011] addi = [.................000.....0010011] sub = [0100000..........000.....0110011] and = [0000000..........111.....0110011] andi = [.................111.....0010011] or = [0000000..........110.....0110011] ori = [.................110.....0010011] xor = [0000000..........100.....0110011] xori = [.................100.....0010011] sll = [0000000..........001.....0110011] slli = [0000000..........001.....0010011] sra = [0100000..........101.....0110011] srai = [0100000..........101.....0010011] srl = [0000000..........101.....0110011] srli = [0000000..........101.....0010011] lui = [.........................0110111] auipc = [.........................0010111] slt = [0000000..........010.....0110011] sltu = [0000000..........011.....0110011] slti = [.................010.....0010011] sltiu = [.................011.....0010011] beq = [.................000.....1100011] bne = [.................001.....1100011] bge = [.................101.....1100011] blt = [.................100.....1100011] bgeu = [.................111.....1100011] bltu = [.................110.....1100011] jal = [.........................1101111] jalr = [.................000.....1100111] lb = [.................000.....0000011] lh = [.................001.....0000011] lw = [.................010.....0000011] sb = [.................000.....0100011] sh = [.................001.....0100011] sw = [.................010.....0100011] lbu = [.................100.....0000011] lhu = [.................101.....0000011] fence = [.000.............000.....0001111] fence.i = [.................001.....0001111] ebreak = [00000000000100000000000001110011] ecall = [00000000000000000000000001110011] mret = [00110000001000000000000001110011] wfi = [00010000010100000000000001110011] csrrc_ro = [............00000011.....1110011] csrrc_rw0 = [............1....011.....1110011] csrrc_rw1 = [.............1...011.....1110011] csrrc_rw2 = [..............1..011.....1110011] csrrc_rw3 = [...............1.011.....1110011] csrrc_rw4 = [................1011.....1110011] csrrci_ro = [............00000111.....1110011] csrrci_rw0 = [............1....111.....1110011] csrrci_rw1 = [.............1...111.....1110011] csrrci_rw2 = [..............1..111.....1110011] csrrci_rw3 = [...............1.111.....1110011] csrrci_rw4 = [................1111.....1110011] csrrs_ro = [............00000010.....1110011] csrrs_rw0 = [............1....010.....1110011] csrrs_rw1 = [.............1...010.....1110011] csrrs_rw2 = [..............1..010.....1110011] csrrs_rw3 = [...............1.010.....1110011] csrrs_rw4 = [................1010.....1110011] csrrsi_ro = [............00000110.....1110011] csrrsi_rw0 = [............1....110.....1110011] csrrsi_rw1 = [.............1...110.....1110011] csrrsi_rw2 = [..............1..110.....1110011] csrrsi_rw3 = [...............1.110.....1110011] csrrsi_rw4 = [................1110.....1110011] csrw = [.................001000001110011] csrrw0 = [.................001....11110011] csrrw1 = [.................001...1.1110011] csrrw2 = [.................001..1..1110011] csrrw3 = [.................001.1...1110011] csrrw4 = [.................0011....1110011] csrwi = [.................101000001110011] csrrwi0 = [.................101....11110011] csrrwi1 = [.................101...1.1110011] csrrwi2 = [.................101..1..1110011] csrrwi3 = [.................101.1...1110011] csrrwi4 = [.................1011....1110011] mul = [0000001..........000.....0110011] mulh = [0000001..........001.....0110011] mulhsu = [0000001..........010.....0110011] mulhu = [0000001..........011.....0110011] div = [0000001..........100.....0110011] divu = [0000001..........101.....0110011] rem = [0000001..........110.....0110011] remu = [0000001..........111.....0110011] .input rv32i = { i[31] i[30] i[29] i[28] i[27] i[26] i[25] i[24] i[23] i[22] i[21] i[20] i[19] i[18] i[17] i[16] i[15] i[14] i[13] i[12] i[11] i[10] i[9] i[8] i[7] i[6] i[5] i[4] i[3] i[2] i[1] i[0] } .output rv32i = { alu rs1 rs2 imm12 rd shimm5 imm20 pc load store lsu add sub land lor lxor sll sra srl slt unsign condbr beq bne bge blt jal by half word csr_read csr_clr csr_set csr_write csr_imm presync postsync ebreak ecall mret mul rs1_sign rs2_sign low div rem fence fence_i clz ctz cpop sext_b sext_h min max pack packu packh rol ror zbb bset bclr binv bext zbs bcompress bdecompress zbe clmul clmulh clmulr zbc grev gorc shfl unshfl xperm_n xperm_b xperm_h zbp crc32_b crc32_h crc32_w crc32c_b crc32c_h crc32c_w zbr bfp zbf sh1add sh2add sh3add zba pm_alu } .decode rv32i[clz] = { alu zbb rs1 rd clz } rv32i[ctz] = { alu zbb rs1 rd ctz } rv32i[cpop] = { alu zbb rs1 rd cpop } rv32i[sext_b] = { alu zbb rs1 rd sext_b} rv32i[sext_h] = { alu zbb rs1 rd sext_h} rv32i[min] = { alu zbb rs1 rs2 rd sub min } rv32i[max] = { alu zbb rs1 rs2 rd sub max } rv32i[minu] = { alu zbb rs1 rs2 rd unsign sub min } rv32i[maxu] = { alu zbb rs1 rs2 rd unsign sub max } rv32i[andn] = { alu zbb zbp rs1 rs2 rd land } rv32i[orn] = { alu zbb zbp rs1 rs2 rd lor } rv32i[xnor] = { alu zbb zbp rs1 rs2 rd lxor } rv32i[packu] = { alu zbp rs1 rs2 rd packu } rv32i[packh] = { alu zbp rs1 rs2 rd packh zbe zbf} rv32i[rol] = { alu zbb zbp rs1 rs2 rd rol } rv32i[ror] = { alu zbb zbp rs1 rs2 rd ror } rv32i[rori] = { alu zbb zbp rs1 rd shimm5 ror } rv32i[bset] = { alu zbs rs1 rs2 rd bset } rv32i[bclr] = { alu zbs rs1 rs2 rd bclr } rv32i[binv] = { alu zbs rs1 rs2 rd binv } rv32i[bext] = { alu zbs rs1 rs2 rd bext } rv32i[bseti] = { alu zbs rs1 rd shimm5 bset } rv32i[bclri] = { alu zbs rs1 rd shimm5 bclr } rv32i[binvi] = { alu zbs rs1 rd shimm5 binv } rv32i[bexti] = { alu zbs rs1 rd shimm5 bext } rv32i[sh1add] = { alu zba rs1 rs2 rd sh1add} rv32i[sh2add] = { alu zba rs1 rs2 rd sh2add} rv32i[sh3add] = { alu zba rs1 rs2 rd sh3add} #v32i[pack] = { alu zbp rs1 rs2 rd pack zbe zbf} rv32i[zext_h] = { alu zbb zbp rs1 rs2 rd pack zbe zbf} # pack with rs2=x0 rv32i[pack{1-31}]= { alu zbp rs1 rs2 rd pack zbe zbf} rv32i[mul] = { mul rs1 rs2 rd low } rv32i[mulh] = { mul rs1 rs2 rd rs1_sign rs2_sign } rv32i[mulhu] = { mul rs1 rs2 rd } rv32i[mulhsu] = { mul rs1 rs2 rd rs1_sign } rv32i[bcompress] = { mul zbe rs1 rs2 rd bcompress } rv32i[bdecompress] = { mul zbe rs1 rs2 rd bdecompress } rv32i[clmul] = { mul zbc rs1 rs2 rd clmul } rv32i[clmulh] = { mul zbc rs1 rs2 rd clmulh} rv32i[clmulr] = { mul zbc rs1 rs2 rd clmulr} rv32i[crc32_b] = { mul zbr rs1 rd crc32_b} rv32i[crc32_h] = { mul zbr rs1 rd crc32_h} rv32i[crc32_w] = { mul zbr rs1 rd crc32_w} rv32i[crc32c_b] = { mul zbr rs1 rd crc32c_b} rv32i[crc32c_h] = { mul zbr rs1 rd crc32c_h} rv32i[crc32c_w] = { mul zbr rs1 rd crc32c_w} rv32i[bfp] = { mul zbf rs1 rs2 rd bfp } rv32i[grev] = { mul zbp rs1 rs2 rd grev } rv32i[grevi{0-23}] = { mul zbp rs1 rd shimm5 grev } rv32i[grevi{25-31}] = { mul zbp rs1 rd shimm5 grev } rv32i[rev8] = { alu zbb zbp rs1 rd shimm5 grev } # grevi24 rv32i[gorc] = { mul zbp rs1 rs2 rd gorc } rv32i[gorci{0-6}] = { mul zbp rs1 rd shimm5 gorc } rv32i[gorci{8-31}] = { mul zbp rs1 rd shimm5 gorc } rv32i[orc_b] = { alu zbb zbp rs1 rd shimm5 gorc } # gorci7 rv32i[shfl] = { mul zbp rs1 rs2 rd shfl } rv32i[shfli] = { mul zbp rs1 rd shimm5 shfl } rv32i[unshfl] = { mul zbp rs1 rs2 rd unshfl} rv32i[unshfli] = { mul zbp rs1 rd shimm5 unshfl} rv32i[xperm_n] = { mul zbp rs1 rs2 rd xperm_n} rv32i[xperm_b] = { mul zbp rs1 rs2 rd xperm_b} rv32i[xperm_h] = { mul zbp rs1 rs2 rd xperm_h} rv32i[div] = { div rs1 rs2 rd } rv32i[divu] = { div rs1 rs2 rd unsign } rv32i[rem] = { div rs1 rs2 rd rem} rv32i[remu] = { div rs1 rs2 rd unsign rem} rv32i[add] = { alu rs1 rs2 rd add pm_alu } rv32i[addi] = { alu rs1 imm12 rd add pm_alu } rv32i[sub] = { alu rs1 rs2 rd sub pm_alu } rv32i[and] = { alu rs1 rs2 rd land pm_alu } rv32i[andi] = { alu rs1 imm12 rd land pm_alu } rv32i[or] = { alu rs1 rs2 rd lor pm_alu } rv32i[ori] = { alu rs1 imm12 rd lor pm_alu } rv32i[xor] = { alu rs1 rs2 rd lxor pm_alu } rv32i[xori] = { alu rs1 imm12 rd lxor pm_alu } rv32i[sll] = { alu rs1 rs2 rd sll pm_alu } rv32i[slli] = { alu rs1 shimm5 rd sll pm_alu } rv32i[sra] = { alu rs1 rs2 rd sra pm_alu } rv32i[srai] = { alu rs1 shimm5 rd sra pm_alu } rv32i[srl] = { alu rs1 rs2 rd srl pm_alu } rv32i[srli] = { alu rs1 shimm5 rd srl pm_alu } rv32i[lui] = { alu imm20 rd lor pm_alu } rv32i[auipc] = { alu imm20 pc rd add pm_alu } rv32i[slt] = { alu rs1 rs2 rd sub slt pm_alu } rv32i[sltu] = { alu rs1 rs2 rd sub slt unsign pm_alu } rv32i[slti] = { alu rs1 imm12 rd sub slt pm_alu } rv32i[sltiu] = { alu rs1 imm12 rd sub slt unsign pm_alu } rv32i[beq] = { alu rs1 rs2 sub condbr beq } rv32i[bne] = { alu rs1 rs2 sub condbr bne } rv32i[bge] = { alu rs1 rs2 sub condbr bge } rv32i[blt] = { alu rs1 rs2 sub condbr blt } rv32i[bgeu] = { alu rs1 rs2 sub condbr bge unsign } rv32i[bltu] = { alu rs1 rs2 sub condbr blt unsign } rv32i[jal] = { alu imm20 rd pc jal } rv32i[jalr] = { alu rs1 rd imm12 jal } rv32i[lb] = { lsu load rs1 rd by } rv32i[lh] = { lsu load rs1 rd half } rv32i[lw] = { lsu load rs1 rd word } rv32i[lbu] = { lsu load rs1 rd by unsign } rv32i[lhu] = { lsu load rs1 rd half unsign } rv32i[sb] = { lsu store rs1 rs2 by } rv32i[sh] = { lsu store rs1 rs2 half } rv32i[sw] = { lsu store rs1 rs2 word } rv32i[fence] = { alu lor fence presync} # fence.i has fence effect in addtion to flush I$ and redirect rv32i[fence.i] = { alu lor fence fence_i presync postsync} # nops for now rv32i[ebreak] = { alu rs1 imm12 rd lor ebreak postsync} rv32i[ecall] = { alu rs1 imm12 rd lor ecall postsync} rv32i[mret] = { alu rs1 imm12 rd lor mret postsync} rv32i[wfi] = { alu rs1 imm12 rd lor pm_alu } # csr means read # csr_read - put csr on rs2 and rs1 0's rv32i[csrrc_ro] = { alu rd csr_read } # put csr on rs2 and make rs1 0's into alu. Save rs1 for csr_clr later rv32i[csrrc_rw{0-4}] = { alu rd csr_read rs1 csr_clr presync postsync } rv32i[csrrci_ro] = { alu rd csr_read } rv32i[csrrci_rw{0-4}] = { alu rd csr_read rs1 csr_clr csr_imm presync postsync } rv32i[csrrs_ro] = { alu rd csr_read } rv32i[csrrs_rw{0-4}] = { alu rd csr_read rs1 csr_set presync postsync } rv32i[csrrsi_ro] = { alu rd csr_read } rv32i[csrrsi_rw{0-4}] = { alu rd csr_read rs1 csr_set csr_imm presync postsync } rv32i[csrrw{0-4}] = { alu rd csr_read rs1 csr_write presync postsync } rv32i[csrrwi{0-4}] = { alu rd csr_read rs1 csr_write csr_imm presync postsync } # optimize csr write only - pipelined rv32i[csrw] = { alu rd rs1 csr_write } rv32i[csrwi] = { alu rd csr_write csr_imm } .end ================================================ FILE: design/dec/el2_dec.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // dec: decode unit - decode, bypassing, ARF, interrupts // //******************************************************************************** // $Id$ // // // Function: Decode // Comments: Decode, dependency scoreboard, ARF // // // A -> D -> EX1 ... WB // //******************************************************************************** module el2_dec import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic free_clk, // Clock always. Through two clock headers. For flops without second clock header built in. input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in. input logic lsu_fastint_stall_any, // needed by lsu for 2nd pass of dma with ecc correction, stall next cycle output logic dec_extint_stall, // Stall on external interrupt output logic dec_i0_decode_d, // Valid instruction at D-stage and not blocked output logic dec_pause_state_cg, // to top for active state clock gating output logic dec_tlu_core_empty, input logic rst_l, // reset, active low // rst_vec is supposed to be connected to a constant in the top level /*pragma coverage off*/ input logic [31:1] rst_vec, // reset vector, from core pins /*pragma coverage on*/ input logic nmi_int, // NMI pin // nmi_vec is supposed to be connected to a constant in the top level /*pragma coverage off*/ input logic [31:1] nmi_vec, // NMI vector, from pins /*pragma coverage on*/ input logic i_cpu_halt_req, // Asynchronous Halt request to CPU input logic i_cpu_run_req, // Asynchronous Restart request to CPU output logic o_cpu_halt_status, // Halt status of core (pmu/fw) output logic o_cpu_halt_ack, // Halt request ack output logic o_cpu_run_ack, // Run request ack output logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request /*pragma coverage off*/ input logic [31:4] core_id, // CORE ID /*pragma coverage on*/ // external MPC halt/run interface input logic mpc_debug_halt_req, // Async halt request input logic mpc_debug_run_req, // Async run request input logic mpc_reset_run_req, // Run/halt after reset output logic mpc_debug_halt_ack, // Halt ack output logic mpc_debug_run_ack, // Run ack output logic debug_brkpt_status, // debug breakpoint input logic exu_pmu_i0_br_misp, // slot 0 branch misp input logic exu_pmu_i0_br_ataken, // slot 0 branch actual taken input logic exu_pmu_i0_pc4, // slot 0 4 byte branch input logic lsu_nonblock_load_valid_m, // valid nonblock load at m input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_m, // -> corresponding tag input logic lsu_nonblock_load_inv_r, // invalidate request for nonblock load r input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_r, // -> corresponding tag input logic lsu_nonblock_load_data_valid, // valid nonblock load data back input logic lsu_nonblock_load_data_error, // nonblock load bus error input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // -> corresponding tag input logic [31:0] lsu_nonblock_load_data, // nonblock load data input logic lsu_pmu_bus_trxn, // D side bus transaction input logic lsu_pmu_bus_misaligned, // D side bus misaligned input logic lsu_pmu_bus_error, // D side bus error input logic lsu_pmu_bus_busy, // D side bus busy input logic lsu_pmu_misaligned_m, // D side load or store misaligned input logic lsu_pmu_load_external_m, // D side bus load input logic lsu_pmu_store_external_m, // D side bus store input logic dma_pmu_dccm_read, // DMA DCCM read input logic dma_pmu_dccm_write, // DMA DCCM write input logic dma_pmu_any_read, // DMA read input logic dma_pmu_any_write, // DMA write input logic [31:1] lsu_fir_addr, // Fast int address input logic [ 1:0] lsu_fir_error, // Fast int lookup error input logic ifu_pmu_instr_aligned, // aligned instructions input logic ifu_pmu_fetch_stall, // fetch unit stalled input logic ifu_pmu_ic_miss, // icache miss input logic ifu_pmu_ic_hit, // icache hit input logic ifu_pmu_bus_error, // Instruction side bus error input logic ifu_pmu_bus_busy, // Instruction side bus busy input logic ifu_pmu_bus_trxn, // Instruction side bus transaction input logic ifu_ic_error_start, // IC single bit error input logic ifu_iccm_rd_ecc_single_err, // ICCM single bit error input logic [ 3:0] lsu_trigger_match_m, input logic dbg_cmd_valid, // debugger abstract command valid input logic dbg_cmd_write, // command is a write input logic [ 1:0] dbg_cmd_type, // command type input logic [31:0] dbg_cmd_addr, // command address input logic [ 1:0] dbg_cmd_wrdata, // command write data, for fence/fence_i input logic ifu_i0_icaf, // icache access fault input logic [1:0] ifu_i0_icaf_type, // icache access fault type input logic ifu_i0_icaf_second, // i0 has access fault on second 2B of 4B inst input logic ifu_i0_dbecc, // icache/iccm double-bit error input logic lsu_idle_any, // lsu idle for halting input el2_br_pkt_t i0_brp, // branch packet input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index input logic [ pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR input logic [ pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag input logic [ $clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index input el2_lsu_error_pkt_t lsu_error_pkt_r, // LSU exception/error packet input logic lsu_single_ecc_error_incr, // LSU inc SB error counter input logic lsu_imprecise_error_load_any, // LSU imprecise load bus error input logic lsu_imprecise_error_store_any, // LSU imprecise store bus error input logic [31:0] lsu_imprecise_error_addr_any, // LSU imprecise bus error address input logic [31:0] exu_div_result, // final div result input logic exu_div_wren, // Divide write enable to GPR input logic [31:0] exu_csr_rs1_x, // rs1 for csr instruction input logic [31:0] lsu_result_m, // load result input logic [31:0] lsu_result_corr_r, // load result - corrected load data input logic lsu_load_stall_any, // This is for blocking loads input logic lsu_store_stall_any, // This is for blocking stores input logic dma_dccm_stall_any, // stall any load/store at decode, pmu event input logic dma_iccm_stall_any, // iccm stalled, pmu event input logic iccm_dma_sb_error, // ICCM DMA single bit error input logic exu_flush_final, // slot0 flush input logic [31:1] exu_npc_r, // next PC input logic [31:0] exu_i0_result_x, // alu result x input logic ifu_i0_valid, // fetch valids to instruction buffer input logic [31:0] ifu_i0_instr, // fetch inst's to instruction buffer input logic [31:1] ifu_i0_pc, // pc's for instruction buffer input logic ifu_i0_pc4, // indication of 4B or 2B for corresponding inst input logic [31:1] exu_i0_pc_x, // pc's for e1 from the alu's input logic mexintpend, // External interrupt pending input logic timer_int, // Timer interrupt pending (from pin) input logic soft_int, // Software interrupt pending (from pin) input logic [7:0] pic_claimid, // PIC claimid input logic [3:0] pic_pl, // PIC priv level input logic mhwakeup, // High priority wakeup output logic [3:0] dec_tlu_meicurpl, // to PIC, Current priv level output logic [3:0] dec_tlu_meipt, // to PIC input logic [70:0] ifu_ic_debug_rd_data, // diagnostic icache read data input logic ifu_ic_debug_rd_data_valid, // diagnostic icache read data valid output el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt, // packet of DICAWICS, DICAD0/1, DICAGO info for icache diagnostics // Debug start input logic dbg_halt_req, // DM requests a halt input logic dbg_resume_req, // DM requests a resume input logic ifu_miss_state_idle, // I-side miss buffer empty output logic dec_tlu_dbg_halted, // Core is halted and ready for debug command output logic dec_tlu_debug_mode, // Core is in debug mode output logic dec_tlu_resume_ack, // Resume acknowledge output logic dec_tlu_flush_noredir_r, // Tell fetch to idle on this flush output logic dec_tlu_mpc_halted_only, // Core is halted only due to MPC output logic dec_tlu_flush_leak_one_r, // single step output logic dec_tlu_flush_err_r, // iside perr/ecc rfpc output logic [31:2] dec_tlu_meihap, // Fast ext int base output logic dec_debug_wdata_rs1_d, // insert debug write data into rs1 at decode output logic [31:0] dec_dbg_rddata, // debug command read data output logic dec_dbg_cmd_done, // abstract command is done output logic dec_dbg_cmd_fail, // abstract command failed (illegal reg address) output el2_trigger_pkt_t [3:0] trigger_pkt_any, // info needed by debug trigger blocks output logic dec_tlu_force_halt, // halt has been forced // Debug end // branch info from pipe0 for errors or counter updates input logic [1:0] exu_i0_br_hist_r, // history input logic exu_i0_br_error_r, // error input logic exu_i0_br_start_error_r, // start error input logic exu_i0_br_valid_r, // valid input logic exu_i0_br_mp_r, // mispredict input logic exu_i0_br_middle_r, // middle of bank // branch info from pipe1 for errors or counter updates input logic exu_i0_br_way_r, // way hit or repl output logic dec_i0_rs1_en_d, // Qualify GPR RS1 data output logic dec_i0_rs2_en_d, // Qualify GPR RS2 data output logic [31:0] gpr_i0_rs1_d, // gpr rs1 data output logic [31:0] gpr_i0_rs2_d, // gpr rs2 data output logic [31:0] dec_i0_immed_d, // immediate data output logic [12:1] dec_i0_br_immed_d, // br immediate data output el2_alu_pkt_t i0_ap, // alu packet output logic dec_i0_alu_decode_d, // schedule on D-stage alu output logic dec_i0_branch_d, // Branch in D-stage output logic dec_i0_select_pc_d, // select pc onto rs1 for jal's output logic [31:1] dec_i0_pc_d, // pc's at decode output logic [ 3:0] dec_i0_rs1_bypass_en_d, // rs1 bypass enable output logic [ 3:0] dec_i0_rs2_bypass_en_d, // rs2 bypass enable output logic [31:0] dec_i0_result_r, // Result R-stage output el2_lsu_pkt_t lsu_p, // lsu packet output logic dec_qual_lsu_d, // LSU instruction at D. Use to quiet LSU operands output el2_mul_pkt_t mul_p, // mul packet output el2_div_pkt_t div_p, // div packet output logic dec_div_cancel, // cancel divide operation output logic [11:0] dec_lsu_offset_d, // 12b offset for load/store addresses output logic dec_csr_ren_d, // CSR read enable output logic [31:0] dec_csr_rddata_d, // CSR read data output logic dec_tlu_flush_lower_r, // tlu flush due to late mp, exception, rfpc, or int output logic dec_tlu_flush_lower_wb, output logic [31:1] dec_tlu_flush_path_r, // tlu flush target output logic dec_tlu_i0_kill_writeb_r, // I0 is flushed, don't writeback any results to arch state output logic dec_tlu_fence_i_r, // flush is a fence_i rfnpc, flush icache output logic [31:1] pred_correct_npc_x, // npc if prediction is correct at e2 stage output el2_br_tlu_pkt_t dec_tlu_br0_r_pkt, // slot 0 branch predictor update packet output logic dec_tlu_perfcnt0, // toggles when slot0 perf counter 0 has an event inc output logic dec_tlu_perfcnt1, // toggles when slot0 perf counter 1 has an event inc output logic dec_tlu_perfcnt2, // toggles when slot0 perf counter 2 has an event inc output logic dec_tlu_perfcnt3, // toggles when slot0 perf counter 3 has an event inc output el2_predict_pkt_t dec_i0_predict_p_d, // prediction packet to alus output logic [pt.BHT_GHR_SIZE-1:0] i0_predict_fghr_d, // DEC predict fghr output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] i0_predict_index_d, // DEC predict index output logic [pt.BTB_BTAG_SIZE-1:0] i0_predict_btag_d, // DEC predict branch tag output logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index, // Fully associt btb error index output logic dec_lsu_valid_raw_d, output logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control output logic [1:0] dec_data_en, // clock-gate control logic output logic [1:0] dec_ctl_en, input logic [15:0] ifu_i0_cinst, // 16b compressed instruction output el2_trace_pkt_t trace_rv_trace_pkt, // trace packet // PMP signals output el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES], output logic [31:0] pmp_pmpaddr[pt.PMP_ENTRIES], `ifdef RV_USER_MODE // Privilege mode output logic priv_mode, output logic priv_mode_eff, output logic priv_mode_ns, // mseccfg CSR content for PMP output el2_mseccfg_pkt_t mseccfg, `endif // feature disable from mfdc output logic dec_tlu_external_ldfwd_disable, // disable external load forwarding output logic dec_tlu_sideeffect_posted_disable, // disable posted stores to side-effect address output logic dec_tlu_core_ecc_disable, // disable core ECC output logic dec_tlu_bpred_disable, // disable branch prediction output logic dec_tlu_wb_coalescing_disable, // disable writebuffer coalescing output logic [2:0] dec_tlu_dma_qos_prty, // DMA QoS priority coming from MFDC [18:16] // clock gating overrides from mcgc output logic dec_tlu_misc_clk_override, // override misc clock domain gating output logic dec_tlu_ifu_clk_override, // override fetch clock domain gating output logic dec_tlu_lsu_clk_override, // override load/store clock domain gating output logic dec_tlu_bus_clk_override, // override bus clock domain gating output logic dec_tlu_pic_clk_override, // override PIC clock domain gating output logic dec_tlu_picio_clk_override, // override PICIO clock domain gating output logic dec_tlu_dccm_clk_override, // override DCCM clock domain gating output logic dec_tlu_icm_clk_override, // override ICCM clock domain gating `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_regfile_if.veer_rf_src regfile, `endif output logic dec_tlu_i0_commit_cmt, // committed i0 instruction // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // Flop scan mode control /*pragma coverage on*/ ); logic dec_tlu_dec_clk_override; // to and from dec blocks logic clk_override; logic dec_ib0_valid_d; logic dec_pmu_instr_decoded; logic dec_pmu_decode_stall; logic dec_pmu_presync_stall; logic dec_pmu_postsync_stall; logic dec_tlu_wr_pause_r; // CSR write to pause reg is at R. logic [4:0] dec_i0_rs1_d; logic [4:0] dec_i0_rs2_d; logic [31:0] dec_i0_instr_d; logic dec_tlu_trace_disable; logic dec_tlu_pipelining_disable; logic [4:0] dec_i0_waddr_r; logic dec_i0_wen_r; logic [31:0] dec_i0_wdata_r; logic dec_csr_wen_r; // csr write enable at wb logic [11:0] dec_csr_rdaddr_r; // read address for csrs logic [11:0] dec_csr_wraddr_r; // write address for csryes logic [31:0] dec_csr_wrdata_r; // csr write data at wb logic [11:0] dec_csr_rdaddr_d; // read address for csr logic dec_csr_legal_d; // csr indicates legal operation logic dec_csr_wen_unq_d; // valid csr with write - for csr legal logic dec_csr_any_unq_d; // valid csr - for csr legal logic dec_csr_stall_int_ff; // csr is mie/mstatus el2_trap_pkt_t dec_tlu_packet_r; logic dec_i0_pc4_d; logic dec_tlu_presync_d; logic dec_tlu_postsync_d; logic dec_tlu_debug_stall; logic [31:0] dec_illegal_inst; logic dec_i0_icaf_d; logic dec_i0_dbecc_d; logic dec_i0_icaf_second_d; logic [3:0] dec_i0_trigger_match_d; logic dec_debug_fence_d; logic dec_nonblock_load_wen; logic [4:0] dec_nonblock_load_waddr; logic dec_tlu_flush_pause_r; el2_br_pkt_t dec_i0_brp; logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] dec_i0_bp_index; logic [pt.BHT_GHR_SIZE-1:0] dec_i0_bp_fghr; logic [pt.BTB_BTAG_SIZE-1:0] dec_i0_bp_btag; logic [$clog2(pt.BTB_SIZE)-1:0] dec_i0_bp_fa_index; // Fully associt btb index logic [31:1] dec_tlu_i0_pc_r; logic dec_tlu_i0_kill_writeb_wb; logic dec_tlu_i0_valid_r; logic dec_pause_state; logic [1:0] dec_i0_icaf_type_d; // i0 instruction access fault type logic dec_tlu_flush_extint; // Fast ext int started logic [31:0] dec_i0_inst_wb; logic [31:1] dec_i0_pc_wb; logic dec_tlu_i0_valid_wb1, dec_tlu_int_valid_wb1; logic [ 4:0] dec_tlu_exc_cause_wb1; logic [31:0] dec_tlu_mtval_wb1; logic dec_tlu_i0_exc_valid_wb1; logic [ 4:0] div_waddr_wb; logic dec_div_active; logic dec_debug_valid_d; assign clk_override = dec_tlu_dec_clk_override; assign dec_dbg_rddata[31:0] = dec_i0_wdata_r[31:0]; el2_dec_ib_ctl #(.pt(pt)) instbuff (.*); el2_dec_decode_ctl #(.pt(pt)) decode (.*); `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_regfile_if regfile_if (); assign regfile.gpr.ra = regfile_if.gpr.ra; assign regfile.gpr.sp = regfile_if.gpr.sp; assign regfile.gpr.fp = regfile_if.gpr.fp; assign regfile.gpr.a0 = regfile_if.gpr.a0; assign regfile.gpr.a1 = regfile_if.gpr.a1; assign regfile.gpr.a2 = regfile_if.gpr.a2; assign regfile.gpr.a3 = regfile_if.gpr.a3; assign regfile.gpr.a4 = regfile_if.gpr.a4; assign regfile.gpr.a5 = regfile_if.gpr.a5; assign regfile.gpr.a6 = regfile_if.gpr.a6; assign regfile.gpr.a7 = regfile_if.gpr.a7; assign regfile.tlu.pc = regfile_if.tlu.pc; assign regfile.tlu.npc = regfile_if.tlu.npc; assign regfile.tlu.mstatus = regfile_if.tlu.mstatus; assign regfile.tlu.mie = regfile_if.tlu.mie; assign regfile.tlu.mtvec = regfile_if.tlu.mtvec; assign regfile.tlu.mscratch = regfile_if.tlu.mscratch; assign regfile.tlu.mepc = regfile_if.tlu.mepc; assign regfile.tlu.mcause = regfile_if.tlu.mcause; assign regfile.tlu.mtval = regfile_if.tlu.mtval; assign regfile.tlu.mip = regfile_if.tlu.mip; assign regfile.tlu.mcyclel = regfile_if.tlu.mcyclel; assign regfile.tlu.mcycleh = regfile_if.tlu.mcycleh; assign regfile.tlu.minstretl = regfile_if.tlu.minstretl; assign regfile.tlu.minstreth = regfile_if.tlu.minstreth; assign regfile.tlu.mrac = regfile_if.tlu.mrac; `endif el2_dec_tlu_ctl #(.pt(pt) ) tlu ( `ifdef RV_LOCKSTEP_REGFILE_ENABLE .regfile(regfile_if.veer_tlu_rf), `endif .*); el2_dec_gpr_ctl #( .pt(pt) ) arf ( .*, `ifdef RV_LOCKSTEP_REGFILE_ENABLE .regfile(regfile_if.veer_gpr_rf), `endif // inputs .raddr0(dec_i0_rs1_d[4:0]), .raddr1(dec_i0_rs2_d[4:0]), .wen0(dec_i0_wen_r), .waddr0(dec_i0_waddr_r[4:0]), .wd0(dec_i0_wdata_r[31:0]), .wen1(dec_nonblock_load_wen), .waddr1(dec_nonblock_load_waddr[4:0]), .wd1(lsu_nonblock_load_data[31:0]), .wen2(exu_div_wren), .waddr2(div_waddr_wb), .wd2(exu_div_result[31:0]), // outputs .rd0(gpr_i0_rs1_d[31:0]), .rd1(gpr_i0_rs2_d[31:0]) ); // Trigger el2_dec_trigger #(.pt(pt)) dec_trigger (.*); // trace assign trace_rv_trace_pkt.trace_rv_i_insn_ip = dec_i0_inst_wb[31:0]; assign trace_rv_trace_pkt.trace_rv_i_address_ip = {dec_i0_pc_wb[31:1], 1'b0}; assign trace_rv_trace_pkt.trace_rv_i_valid_ip = dec_tlu_int_valid_wb1 | dec_tlu_i0_valid_wb1 | dec_tlu_i0_exc_valid_wb1; assign trace_rv_trace_pkt.trace_rv_i_exception_ip = dec_tlu_int_valid_wb1 | dec_tlu_i0_exc_valid_wb1; assign trace_rv_trace_pkt.trace_rv_i_ecause_ip = dec_tlu_exc_cause_wb1[4:0]; // replicate across ports assign trace_rv_trace_pkt.trace_rv_i_interrupt_ip = dec_tlu_int_valid_wb1; assign trace_rv_trace_pkt.trace_rv_i_tval_ip = dec_tlu_mtval_wb1[31:0]; // replicate across ports // end trace endmodule // el2_dec ================================================ FILE: design/dec/el2_dec_decode_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_dec_decode_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic dec_tlu_trace_disable, input logic dec_debug_valid_d, input logic dec_tlu_flush_extint, // Flush external interrupt input logic dec_tlu_force_halt, // invalidate nonblock load cam on a force halt event output logic dec_extint_stall, // Stall from external interrupt input logic [15:0] ifu_i0_cinst, // 16b compressed instruction output logic [31:0] dec_i0_inst_wb, // 32b instruction at wb+1 for trace encoder output logic [31:1] dec_i0_pc_wb, // 31b pc at wb+1 for trace encoder input logic lsu_nonblock_load_valid_m, // valid nonblock load at m input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_m, // -> corresponding tag input logic lsu_nonblock_load_inv_r, // invalidate request for nonblock load r input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_r, // -> corresponding tag input logic lsu_nonblock_load_data_valid, // valid nonblock load data back input logic lsu_nonblock_load_data_error, // nonblock load bus error input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // -> corresponding tag input logic [3:0] dec_i0_trigger_match_d, // i0 decode trigger matches input logic dec_tlu_wr_pause_r, // pause instruction at r input logic dec_tlu_pipelining_disable, // pipeline disable - presync, i0 decode only input logic [3:0] lsu_trigger_match_m, // lsu trigger matches input logic lsu_pmu_misaligned_m, // perf mon: load/store misalign input logic dec_tlu_debug_stall, // debug stall decode input logic dec_tlu_flush_leak_one_r, // leak1 instruction input logic dec_debug_fence_d, // debug fence instruction input logic [1:0] dbg_cmd_wrdata, // disambiguate fence, fence_i input logic dec_i0_icaf_d, // icache access fault input logic dec_i0_icaf_second_d, // i0 instruction access fault on second 2B of 4B inst input logic [1:0] dec_i0_icaf_type_d, // i0 instruction access fault type input logic dec_i0_dbecc_d, // icache/iccm double-bit error input el2_br_pkt_t dec_i0_brp, // branch packet input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] dec_i0_bp_index, // i0 branch index input logic [pt.BHT_GHR_SIZE-1:0] dec_i0_bp_fghr, // BP FGHR input logic [pt.BTB_BTAG_SIZE-1:0] dec_i0_bp_btag, // BP tag input logic [$clog2(pt.BTB_SIZE)-1:0] dec_i0_bp_fa_index, // Fully associt btb index input logic lsu_idle_any, // lsu idle: if fence instr & ~lsu_idle then stall decode input logic lsu_load_stall_any, // stall any load at decode input logic lsu_store_stall_any, // stall any store at decode input logic dma_dccm_stall_any, // stall any load/store at decode input logic exu_div_wren, // nonblocking divide write enable to GPR. input logic dec_tlu_i0_kill_writeb_wb, // I0 is flushed, don't writeback any results to arch state input logic dec_tlu_flush_lower_wb, // trap lower flush input logic dec_tlu_i0_kill_writeb_r, // I0 is flushed, don't writeback any results to arch state input logic dec_tlu_flush_lower_r, // trap lower flush input logic dec_tlu_flush_pause_r, // don't clear pause state on initial lower flush input logic dec_tlu_presync_d, // CSR read needs to be presync'd input logic dec_tlu_postsync_d, // CSR ops that need to be postsync'd input logic dec_i0_pc4_d, // inst is 4B inst else 2B input logic [31:0] dec_csr_rddata_d, // csr read data at wb input logic dec_csr_legal_d, // csr indicates legal operation input logic [31:0] exu_csr_rs1_x, // rs1 for csr instr input logic [31:0] lsu_result_m, // load result input logic [31:0] lsu_result_corr_r, // load result - corrected data for writing gpr's, not for bypassing input logic exu_flush_final, // lower flush or i0 flush at X or D input logic [31:1] exu_i0_pc_x, // pcs at e1 input logic [31:0] dec_i0_instr_d, // inst at decode input logic dec_ib0_valid_d, // inst valid at decode input logic [31:0] exu_i0_result_x, // from primary alu's input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in. input logic clk_override, // Override non-functional clock gating input logic rst_l, // Flop reset output logic dec_i0_rs1_en_d, // rs1 enable at decode output logic dec_i0_rs2_en_d, // rs2 enable at decode output logic [4:0] dec_i0_rs1_d, // rs1 logical source output logic [4:0] dec_i0_rs2_d, // rs2 logical source output logic [31:0] dec_i0_immed_d, // 32b immediate data decode output logic [12:1] dec_i0_br_immed_d, // 12b branch immediate output el2_alu_pkt_t i0_ap, // alu packets output logic dec_i0_decode_d, // i0 decode output logic dec_i0_alu_decode_d, // decode to D-stage alu output logic dec_i0_branch_d, // Branch in D-stage output logic [4:0] dec_i0_waddr_r, // i0 logical source to write to gpr's output logic dec_i0_wen_r, // i0 write enable output logic [31:0] dec_i0_wdata_r, // i0 write data output logic dec_i0_select_pc_d, // i0 select pc for rs1 - branches output logic [3:0] dec_i0_rs1_bypass_en_d, // i0 rs1 bypass enable output logic [3:0] dec_i0_rs2_bypass_en_d, // i0 rs2 bypass enable output logic [31:0] dec_i0_result_r, // Result R-stage output el2_lsu_pkt_t lsu_p, // load/store packet output logic dec_qual_lsu_d, // LSU instruction at D. Use to quiet LSU operands output el2_mul_pkt_t mul_p, // multiply packet output el2_div_pkt_t div_p, // divide packet output logic [4:0] div_waddr_wb, // DIV write address to GPR output logic dec_div_cancel, // cancel the divide operation output logic dec_lsu_valid_raw_d, output logic [11:0] dec_lsu_offset_d, output logic dec_csr_ren_d, // valid csr decode output logic dec_csr_wen_unq_d, // valid csr with write - for csr legal output logic dec_csr_any_unq_d, // valid csr - for csr legal output logic [11:0] dec_csr_rdaddr_d, // read address for csr output logic dec_csr_wen_r, // csr write enable at r output logic [11:0] dec_csr_rdaddr_r, // read address for csr output logic [11:0] dec_csr_wraddr_r, // write address for csr output logic [31:0] dec_csr_wrdata_r, // csr write data at r output logic dec_csr_stall_int_ff, // csr is mie/mstatus output dec_tlu_i0_valid_r, // i0 valid inst at c output el2_trap_pkt_t dec_tlu_packet_r, // trap packet output logic [31:1] dec_tlu_i0_pc_r, // i0 trap pc output logic [31:0] dec_illegal_inst, // illegal inst output logic [31:1] pred_correct_npc_x, // npc e2 if the prediction is correct output el2_predict_pkt_t dec_i0_predict_p_d, // i0 predict packet decode output logic [pt.BHT_GHR_SIZE-1:0] i0_predict_fghr_d, // i0 predict fghr output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] i0_predict_index_d, // i0 predict index output logic [pt.BTB_BTAG_SIZE-1:0] i0_predict_btag_d, // i0_predict branch tag output logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index, // Fully associt btb error index output logic [1:0] dec_data_en, // clock-gating logic output logic [1:0] dec_ctl_en, output logic dec_pmu_instr_decoded, // number of instructions decode this cycle encoded output logic dec_pmu_decode_stall, // decode is stalled output logic dec_pmu_presync_stall, // decode has presync stall output logic dec_pmu_postsync_stall, // decode has postsync stall output logic dec_nonblock_load_wen, // write enable for nonblock load output logic [4:0] dec_nonblock_load_waddr, // logical write addr for nonblock load output logic dec_pause_state, // core in pause state output logic dec_pause_state_cg, // pause state for clock-gating output logic dec_div_active, // non-block divide is active // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); el2_dec_pkt_t i0_dp_raw, i0_dp; logic [31:0] i0; logic i0_valid_d; logic [31:0] i0_result_r; logic [2:0] i0_rs1bypass, i0_rs2bypass; logic i0_jalimm20; logic i0_uiimm20; logic lsu_decode_d; logic [31:0] i0_immed_d; logic i0_presync; logic i0_postsync; logic postsync_stall; logic ps_stall; logic prior_inflight, prior_inflight_wb; logic csr_clr_d, csr_set_d, csr_write_d; logic csr_clr_x,csr_set_x,csr_write_x,csr_imm_x; logic [31:0] csr_mask_x; logic [31:0] write_csr_data_x; logic [31:0] write_csr_data_in; logic [31:0] write_csr_data; logic csr_data_wen; logic [4:0] csrimm_x; logic [31:0] csr_rddata_x; logic mul_decode_d; logic div_decode_d; logic div_e1_to_r; logic div_flush; logic div_active_in; logic div_active; logic i0_nonblock_div_stall; logic i0_div_prior_div_stall; logic nonblock_div_cancel; logic i0_legal; logic shift_illegal; logic illegal_inst_en; logic illegal_lockout_in, illegal_lockout; logic i0_legal_decode_d; logic i0_exulegal_decode_d, i0_exudecode_d, i0_exublock_d; logic [12:1] last_br_immed_d; logic i0_rs1_depend_i0_x, i0_rs1_depend_i0_r; logic i0_rs2_depend_i0_x, i0_rs2_depend_i0_r; logic i0_div_decode_d; logic i0_load_block_d; logic [1:0] i0_rs1_depth_d, i0_rs2_depth_d; logic i0_load_stall_d; logic i0_store_stall_d; logic i0_predict_nt, i0_predict_t; logic i0_notbr_error, i0_br_toffset_error; logic i0_ret_error; logic i0_br_error; logic i0_br_error_all; logic [11:0] i0_br_offset; logic [20:1] i0_pcall_imm; // predicted jal's logic i0_pcall_12b_offset; logic i0_pcall_raw; logic i0_pcall_case; logic i0_pcall; logic i0_pja_raw; logic i0_pja_case; logic i0_pja; logic i0_pret_case; logic i0_pret_raw, i0_pret; logic i0_jal; // jal's that are not predicted logic i0_predict_br; logic store_data_bypass_d, store_data_bypass_m; el2_class_pkt_t i0_rs1_class_d, i0_rs2_class_d; el2_class_pkt_t i0_d_c, i0_x_c, i0_r_c; logic i0_ap_pc2, i0_ap_pc4; logic i0_rd_en_d; logic load_ldst_bypass_d; logic leak1_i0_stall_in, leak1_i0_stall; logic leak1_i1_stall_in, leak1_i1_stall; logic leak1_mode; logic i0_csr_write_only_d; logic prior_inflight_x, prior_inflight_eff; logic any_csr_d; logic prior_csr_write; logic [3:0] i0_pipe_en; logic i0_r_ctl_en, i0_x_ctl_en, i0_wb_ctl_en; logic i0_x_data_en, i0_r_data_en, i0_wb_data_en; logic debug_fence_i; logic debug_fence; logic i0_csr_write; logic presync_stall; logic i0_instr_error; logic i0_icaf_d; logic clear_pause; logic pause_state_in, pause_state; logic pause_stall; logic i0_brp_valid; logic nonblock_load_cancel; logic lsu_idle; logic lsu_pmu_misaligned_r; logic csr_ren_qual_d; logic csr_read_x; logic i0_block_d; logic i0_block_raw_d; // This is use to create the raw valid logic ps_stall_in; logic [31:0] i0_result_x; el2_dest_pkt_t d_d, x_d, r_d, wbd; el2_dest_pkt_t x_d_in, r_d_in; el2_trap_pkt_t d_t, x_t, x_t_in, r_t_in, r_t; logic [3:0] lsu_trigger_match_r; logic [31:1] dec_i0_pc_r; logic csr_read, csr_write; logic i0_br_unpred; logic nonblock_load_valid_m_delay; logic i0_wen_r; logic tlu_wr_pause_r1; logic tlu_wr_pause_r2; logic flush_final_r; logic bitmanip_zbb_legal; logic bitmanip_zbs_legal; logic bitmanip_zbe_legal; logic bitmanip_zbc_legal; logic bitmanip_zbp_legal; logic bitmanip_zbr_legal; logic bitmanip_zbf_legal; logic bitmanip_zba_legal; logic bitmanip_zbb_zbp_legal; logic bitmanip_zbp_zbe_zbf_legal; logic bitmanip_zbb_zbp_zbe_zbf_legal; logic bitmanip_legal; localparam NBLOAD_SIZE = pt.LSU_NUM_NBLOAD; localparam NBLOAD_SIZE_MSB = int'(pt.LSU_NUM_NBLOAD)-1; localparam NBLOAD_TAG_MSB = pt.LSU_NUM_NBLOAD_WIDTH-1; logic cam_write, cam_inv_reset, cam_data_reset; logic [NBLOAD_TAG_MSB:0] cam_write_tag, cam_inv_reset_tag, cam_data_reset_tag; logic [NBLOAD_SIZE_MSB:0] cam_wen; logic [NBLOAD_TAG_MSB:0] load_data_tag; logic [NBLOAD_SIZE_MSB:0] nonblock_load_write; el2_load_cam_pkt_t [NBLOAD_SIZE_MSB:0] cam; el2_load_cam_pkt_t [NBLOAD_SIZE_MSB:0] cam_in; el2_load_cam_pkt_t [NBLOAD_SIZE_MSB:0] cam_raw; logic [4:0] nonblock_load_rd; logic i0_nonblock_load_stall; logic i0_nonblock_boundary_stall; logic i0_rs1_nonblock_load_bypass_en_d, i0_rs2_nonblock_load_bypass_en_d; logic i0_load_kill_wen_r; logic found; logic [NBLOAD_SIZE_MSB:0] cam_inv_reset_val, cam_data_reset_val; logic debug_fence_raw; logic [31:0] i0_result_r_raw; logic [31:0] i0_result_corr_r; logic [12:1] last_br_immed_x; logic [31:0] i0_inst_d; logic [31:0] i0_inst_x; logic [31:0] i0_inst_r; logic [31:0] i0_inst_wb_in; logic [31:0] i0_inst_wb; logic [31:1] i0_pc_wb; logic i0_wb_en; logic trace_enable; logic debug_valid_x; el2_inst_pkt_t i0_itype; el2_reg_pkt_t i0r; rvdffie #(8) misc1ff (.*, .clk(free_l2clk), .din( {leak1_i1_stall_in,leak1_i0_stall_in,dec_tlu_flush_extint,pause_state_in ,dec_tlu_wr_pause_r, tlu_wr_pause_r1,illegal_lockout_in,ps_stall_in}), .dout({leak1_i1_stall, leak1_i0_stall, dec_extint_stall, pause_state, tlu_wr_pause_r1,tlu_wr_pause_r2,illegal_lockout, ps_stall }) ); rvdffie #(8) misc2ff (.*, .clk(free_l2clk), .din( {lsu_trigger_match_m[3:0],lsu_pmu_misaligned_m,div_active_in,exu_flush_final, dec_debug_valid_d}), .dout({lsu_trigger_match_r[3:0],lsu_pmu_misaligned_r,div_active, flush_final_r, debug_valid_x}) ); if(pt.BTB_ENABLE==1) begin // branch prediction // in leak1_mode, ignore any predictions for i0, treat branch as if we haven't seen it before // in leak1 mode, also ignore branch errors for i0 assign i0_brp_valid = dec_i0_brp.valid & ~leak1_mode & ~i0_icaf_d; assign dec_i0_predict_p_d.misp = '0; assign dec_i0_predict_p_d.ataken = '0; assign dec_i0_predict_p_d.boffset = '0; assign dec_i0_predict_p_d.pcall = i0_pcall; // don't mark as pcall if branch error assign dec_i0_predict_p_d.pja = i0_pja; assign dec_i0_predict_p_d.pret = i0_pret; assign dec_i0_predict_p_d.prett[31:1] = dec_i0_brp.prett[31:1]; assign dec_i0_predict_p_d.pc4 = dec_i0_pc4_d; assign dec_i0_predict_p_d.hist[1:0] = dec_i0_brp.hist[1:0]; assign dec_i0_predict_p_d.valid = i0_brp_valid & i0_legal_decode_d; assign i0_notbr_error = i0_brp_valid & ~(i0_dp_raw.condbr | i0_pcall_raw | i0_pja_raw | i0_pret_raw); // no toffset error for a pret assign i0_br_toffset_error = i0_brp_valid & dec_i0_brp.hist[1] & (dec_i0_brp.toffset[11:0] != i0_br_offset[11:0]) & ~i0_pret_raw; assign i0_ret_error = i0_brp_valid & (dec_i0_brp.ret ^ i0_pret_raw); assign i0_br_error = dec_i0_brp.br_error | i0_notbr_error | i0_br_toffset_error | i0_ret_error; assign dec_i0_predict_p_d.br_error = i0_br_error & i0_legal_decode_d & ~leak1_mode; assign dec_i0_predict_p_d.br_start_error = dec_i0_brp.br_start_error & i0_legal_decode_d & ~leak1_mode; assign i0_predict_index_d[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = dec_i0_bp_index; assign i0_predict_btag_d[pt.BTB_BTAG_SIZE-1:0] = dec_i0_bp_btag[pt.BTB_BTAG_SIZE-1:0]; assign i0_br_error_all = (i0_br_error | dec_i0_brp.br_start_error) & ~leak1_mode; assign dec_i0_predict_p_d.toffset[11:0] = i0_br_offset[11:0]; assign i0_predict_fghr_d[pt.BHT_GHR_SIZE-1:0] = dec_i0_bp_fghr[pt.BHT_GHR_SIZE-1:0]; assign dec_i0_predict_p_d.way = dec_i0_brp.way; if(pt.BTB_FULLYA) begin : genblock logic btb_error_found, btb_error_found_f; logic [$clog2(pt.BTB_SIZE)-1:0] fa_error_index_ns; assign btb_error_found = (i0_br_error_all | btb_error_found_f) & ~dec_tlu_flush_lower_r; assign fa_error_index_ns = (i0_br_error_all & ~btb_error_found_f) ? dec_i0_bp_fa_index : dec_fa_error_index; rvdff #($clog2(pt.BTB_SIZE)+1) btberrorfa_f (.*, .clk(active_clk), .din({btb_error_found, fa_error_index_ns}), .dout({btb_error_found_f, dec_fa_error_index})); end else assign dec_fa_error_index = 'b0; // end end // if (pt.BTB_ENABLE==1) else begin always_comb begin dec_i0_predict_p_d = '0; dec_i0_predict_p_d.pcall = i0_pcall; // don't mark as pcall if branch error dec_i0_predict_p_d.pja = i0_pja; dec_i0_predict_p_d.pret = i0_pret; dec_i0_predict_p_d.pc4 = dec_i0_pc4_d; end assign i0_br_error_all = '0; assign i0_predict_index_d = '0; assign i0_predict_btag_d = '0; assign i0_predict_fghr_d = '0; assign i0_brp_valid = '0; end // else: !if(pt.BTB_ENABLE==1) // on br error turn anything into a nop // on i0 instruction fetch access fault turn anything into a nop // nop => alu rs1 imm12 rd lor assign i0_icaf_d = dec_i0_icaf_d | dec_i0_dbecc_d; assign i0_instr_error = i0_icaf_d; always_comb begin i0_dp = i0_dp_raw; if (i0_br_error_all | i0_instr_error) begin i0_dp = '0; i0_dp.alu = 1'b1; i0_dp.rs1 = 1'b1; i0_dp.rs2 = 1'b1; i0_dp.lor = 1'b1; i0_dp.legal = 1'b1; i0_dp.postsync = 1'b1; end end assign i0[31:0] = dec_i0_instr_d[31:0]; assign dec_i0_select_pc_d = i0_dp.pc; // branches that can be predicted assign i0_predict_br = i0_dp.condbr | i0_pcall | i0_pja | i0_pret; assign i0_predict_nt = ~(dec_i0_brp.hist[1] & i0_brp_valid) & i0_predict_br; assign i0_predict_t = (dec_i0_brp.hist[1] & i0_brp_valid) & i0_predict_br; assign i0_ap.add = i0_dp.add; assign i0_ap.sub = i0_dp.sub; assign i0_ap.land = i0_dp.land; assign i0_ap.lor = i0_dp.lor; assign i0_ap.lxor = i0_dp.lxor; assign i0_ap.sll = i0_dp.sll; assign i0_ap.srl = i0_dp.srl; assign i0_ap.sra = i0_dp.sra; assign i0_ap.slt = i0_dp.slt; assign i0_ap.unsign = i0_dp.unsign; assign i0_ap.beq = i0_dp.beq; assign i0_ap.bne = i0_dp.bne; assign i0_ap.blt = i0_dp.blt; assign i0_ap.bge = i0_dp.bge; assign i0_ap.clz = i0_dp.clz; assign i0_ap.ctz = i0_dp.ctz; assign i0_ap.cpop = i0_dp.cpop; assign i0_ap.sext_b = i0_dp.sext_b; assign i0_ap.sext_h = i0_dp.sext_h; assign i0_ap.sh1add = i0_dp.sh1add; assign i0_ap.sh2add = i0_dp.sh2add; assign i0_ap.sh3add = i0_dp.sh3add; assign i0_ap.zba = i0_dp.zba; assign i0_ap.min = i0_dp.min; assign i0_ap.max = i0_dp.max; assign i0_ap.pack = i0_dp.pack; assign i0_ap.packu = i0_dp.packu; assign i0_ap.packh = i0_dp.packh; assign i0_ap.rol = i0_dp.rol; assign i0_ap.ror = i0_dp.ror; assign i0_ap.grev = i0_dp.grev; assign i0_ap.gorc = i0_dp.gorc; assign i0_ap.zbb = i0_dp.zbb; assign i0_ap.bset = i0_dp.bset; assign i0_ap.bclr = i0_dp.bclr; assign i0_ap.binv = i0_dp.binv; assign i0_ap.bext = i0_dp.bext; assign i0_ap.csr_write = i0_csr_write_only_d; assign i0_ap.csr_imm = i0_dp.csr_imm; assign i0_ap.jal = i0_jal; assign i0_ap_pc2 = ~dec_i0_pc4_d; assign i0_ap_pc4 = dec_i0_pc4_d; assign i0_ap.predict_nt = i0_predict_nt; assign i0_ap.predict_t = i0_predict_t; // non block load cam logic always_comb begin found = 0; for (int i=0; i coredecode.e // 2) espresso -Dso -oeqntott < coredecode.e | addassign -pre out. > equations // 3) copy-paste assignments from the file "equations" and replace ones below. // // To generate instruction legality check equation do: // 1) coredecode -in decode -legal > legal.e // 2) espresso -Dso -oeqntott < legal.e | addassign -pre out. > legal // 3) copy-paste assignment from the file "legal" and replace the one below. module el2_dec_dec_ctl import el2_pkg::*; ( input logic [31:0] inst, output el2_dec_pkt_t out ); logic [31:0] i; assign i[31:0] = inst[31:0]; assign out.alu = (i[30]&i[24]&i[23]&!i[22]&!i[21]&!i[20]&i[14]&!i[5]&i[4]) | (i[30] &!i[27]&!i[24]&i[4]) | (!i[30]&!i[25]&i[13]&i[12]) | (!i[29]&!i[27] &!i[5]&i[4]) | (i[27]&i[25]&i[14]&i[4]) | (!i[29]&!i[25]&!i[13]&!i[12] &i[4]) | (i[29]&i[27]&!i[14]&i[12]&i[4]) | (!i[27]&i[14]&!i[5]&i[4]) | ( i[30]&!i[29]&!i[13]&i[4]) | (!i[27]&!i[25]&i[5]&i[4]) | (i[13]&!i[5] &i[4]) | (i[6]) | (!i[30]&i[29]&!i[24]&!i[23]&i[22]&i[21]&i[20]&!i[5] &i[4]) | (i[2]) | (!i[12]&!i[5]&i[4]); assign out.rs1 = (!i[13]&i[11]&!i[2]) | (!i[13]&i[10]&!i[2]) | (i[19]&i[13]&!i[2]) | ( !i[13]&i[9]&!i[2]) | (i[18]&i[13]&!i[2]) | (!i[13]&i[8]&!i[2]) | ( i[17]&i[13]&!i[2]) | (!i[13]&i[7]&!i[2]) | (i[16]&i[13]&!i[2]) | ( i[15]&i[13]&!i[2]) | (!i[4]&!i[2]) | (!i[14]&!i[13]&i[6]&!i[3]) | ( !i[6]&!i[2]); assign out.rs2 = (i[5] & !i[4] & !i[2]) | (!i[6] & i[5] & !i[2]); assign out.imm12 = (!i[4]&!i[3]&i[2]) | (i[13]&!i[5]&i[4]&!i[2]) | (!i[13]&!i[12] &i[6]&i[4]) | (!i[12]&!i[5]&i[4]&!i[2]); assign out.rd = (!i[5] & !i[2]) | (i[5] & i[2]) | (i[4]); assign out.shimm5 = (!i[29]&!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (i[27]&!i[13]&i[12] &!i[5]&i[4]&!i[2]) | (i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]); assign out.imm20 = (i[5] & i[3]) | (i[4] & i[2]); assign out.pc = (!i[5] & !i[3] & i[2]) | (i[5] & i[3]); assign out.load = (!i[5] & !i[4] & !i[2]); assign out.store = (!i[6] & i[5] & !i[4]); assign out.lsu = (!i[6] & !i[4] & !i[2]); assign out.add = (!i[14]&!i[13]&!i[12]&!i[5]&i[4]) | (!i[5]&!i[3]&i[2]) | (!i[30] &!i[25]&!i[14]&!i[13]&!i[12]&!i[6]&i[4]&!i[2]); assign out.sub = (i[30]&!i[14]&!i[12]&!i[6]&i[5]&i[4]&!i[2]) | (!i[29]&!i[25]&!i[14] &i[13]&!i[6]&i[4]&!i[2]) | (i[27]&i[25]&i[14]&!i[6]&i[5]&!i[2]) | ( !i[14]&i[13]&!i[5]&i[4]&!i[2]) | (i[6]&!i[4]&!i[2]); assign out.land = (!i[27]&!i[25]&i[14]&i[13]&i[12]&!i[6]&!i[2]) | (i[14]&i[13]&i[12] &!i[5]&!i[2]); assign out.lor = (!i[29]&!i[27]&!i[25]&i[14]&i[13]&!i[12]&!i[6]&!i[2]) | (!i[6]&i[3]) | ( i[5]&i[4]&i[2]) | (!i[13]&!i[12]&i[6]&i[4]) | (i[14]&i[13]&!i[12] &!i[5]&!i[2]); assign out.lxor = (!i[29]&!i[27]&!i[25]&i[14]&!i[13]&!i[12]&i[4]&!i[2]) | (i[14] &!i[13]&!i[12]&!i[5]&i[4]&!i[2]); assign out.sll = (!i[29] & !i[27] & !i[25] & !i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.sra = (i[30] & !i[29] & !i[27] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.srl = (!i[30] & !i[27] & !i[25] & i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.slt = (!i[29]&!i[25]&!i[14]&i[13]&!i[6]&i[4]&!i[2]) | (!i[14]&i[13]&!i[5] &i[4]&!i[2]); assign out.unsign = (!i[14]&i[13]&i[12]&!i[5]&!i[2]) | (i[13]&i[6]&!i[4]&!i[2]) | ( i[14]&!i[5]&!i[4]) | (!i[25]&!i[14]&i[13]&i[12]&!i[6]&!i[2]) | ( i[25]&i[14]&i[12]&!i[6]&i[5]&!i[2]); assign out.condbr = (i[6] & !i[4] & !i[2]); assign out.beq = (!i[14] & !i[12] & i[6] & !i[4] & !i[2]); assign out.bne = (!i[14] & i[12] & i[6] & !i[4] & !i[2]); assign out.bge = (i[14] & i[12] & i[5] & !i[4] & !i[2]); assign out.blt = (i[14] & !i[12] & i[5] & !i[4] & !i[2]); assign out.jal = (i[6] & i[2]); assign out.by = (!i[13] & !i[12] & !i[6] & !i[4] & !i[2]); assign out.half = (i[12] & !i[6] & !i[4] & !i[2]); assign out.word = (i[13] & !i[6] & !i[4]); assign out.csr_read = (i[13]&i[6]&i[4]) | (i[7]&i[6]&i[4]) | (i[8]&i[6]&i[4]) | ( i[9]&i[6]&i[4]) | (i[10]&i[6]&i[4]) | (i[11]&i[6]&i[4]); assign out.csr_clr = (i[15]&i[13]&i[12]&i[6]&i[4]) | (i[16]&i[13]&i[12]&i[6]&i[4]) | ( i[17]&i[13]&i[12]&i[6]&i[4]) | (i[18]&i[13]&i[12]&i[6]&i[4]) | ( i[19]&i[13]&i[12]&i[6]&i[4]); assign out.csr_set = (i[15]&!i[12]&i[6]&i[4]) | (i[16]&!i[12]&i[6]&i[4]) | (i[17] &!i[12]&i[6]&i[4]) | (i[18]&!i[12]&i[6]&i[4]) | (i[19]&!i[12]&i[6] &i[4]); assign out.csr_write = (!i[13] & i[12] & i[6] & i[4]); assign out.csr_imm = (i[14]&!i[13]&i[6]&i[4]) | (i[15]&i[14]&i[6]&i[4]) | (i[16] &i[14]&i[6]&i[4]) | (i[17]&i[14]&i[6]&i[4]) | (i[18]&i[14]&i[6]&i[4]) | ( i[19]&i[14]&i[6]&i[4]); assign out.presync = (!i[5]&i[3]) | (!i[13]&i[7]&i[6]&i[4]) | (!i[13]&i[8]&i[6]&i[4]) | ( !i[13]&i[9]&i[6]&i[4]) | (!i[13]&i[10]&i[6]&i[4]) | (!i[13]&i[11] &i[6]&i[4]) | (i[15]&i[13]&i[6]&i[4]) | (i[16]&i[13]&i[6]&i[4]) | ( i[17]&i[13]&i[6]&i[4]) | (i[18]&i[13]&i[6]&i[4]) | (i[19]&i[13]&i[6] &i[4]); assign out.postsync = (!i[22]&!i[13]&!i[12]&i[6]&i[4]) | (i[12]&!i[5]&i[3]) | ( !i[13]&i[7]&i[6]&i[4]) | (!i[13]&i[8]&i[6]&i[4]) | (!i[13]&i[9]&i[6] &i[4]) | (!i[13]&i[10]&i[6]&i[4]) | (!i[13]&i[11]&i[6]&i[4]) | ( i[15]&i[13]&i[6]&i[4]) | (i[16]&i[13]&i[6]&i[4]) | (i[17]&i[13]&i[6] &i[4]) | (i[18]&i[13]&i[6]&i[4]) | (i[19]&i[13]&i[6]&i[4]); assign out.ebreak = (!i[22] & i[20] & !i[13] & !i[12] & i[6] & i[4]); assign out.ecall = (!i[21] & !i[20] & !i[13] & !i[12] & i[6] & i[4]); assign out.mret = (i[29] & !i[13] & !i[12] & i[6] & i[4]); assign out.mul = (i[29]&!i[27]&i[24]&!i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (i[30] &i[27]&i[13]&!i[6]&i[5]&i[4]&!i[2]) | (i[29]&i[27]&!i[23]&!i[20] &i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (i[29]&i[27]&!i[21]&i[20] &i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (i[29]&i[27]&i[24]&i[21] &i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (i[29]&i[27]&!i[24]&!i[22] &i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (!i[30]&i[29]&i[23]&i[14] &!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (i[30]&i[29]&i[27]&i[22]&i[14] &!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (i[27]&!i[25]&i[13]&!i[12]&!i[6] &i[5]&i[4]&!i[2]) | (!i[30]&!i[29]&i[27]&!i[25]&!i[13]&i[12]&!i[6] &i[4]&!i[2]) | (i[25]&!i[14]&!i[6]&i[5]&i[4]&!i[2]) | (i[29]&i[27] &i[14]&!i[6]&i[5]&!i[2]); assign out.rs1_sign = (!i[27]&i[25]&!i[14]&i[13]&!i[12]&!i[6]&i[5]&i[4]&!i[2]) | ( !i[27]&i[25]&!i[14]&!i[13]&i[12]&!i[6]&i[4]&!i[2]); assign out.rs2_sign = (!i[27] & i[25] & !i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.low = (i[25] & !i[14] & !i[13] & !i[12] & i[5] & i[4] & !i[2]); assign out.div = (!i[27] & i[25] & i[14] & !i[6] & i[5] & !i[2]); assign out.rem = (!i[27] & i[25] & i[14] & i[13] & !i[6] & i[5] & !i[2]); assign out.fence = (!i[5] & i[3]); assign out.fence_i = (i[12] & !i[5] & i[3]); assign out.clz = (i[29]&!i[27]&!i[24]&!i[22]&!i[21]&!i[20]&!i[14]&!i[13]&i[12]&!i[5] &i[4]&!i[2]); assign out.ctz = (i[29]&!i[27]&!i[24]&!i[22]&i[20]&!i[14]&!i[13]&i[12]&!i[5]&i[4] &!i[2]); assign out.cpop = (i[29]&!i[27]&!i[24]&i[21]&!i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]); assign out.sext_b = (i[29]&!i[27]&i[22]&!i[20]&!i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]); assign out.sext_h = (i[29]&!i[27]&i[22]&i[20]&!i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]); assign out.min = (i[27] & i[25] & i[14] & !i[13] & !i[6] & i[5] & !i[2]); assign out.max = (i[27] & i[25] & i[14] & i[13] & !i[6] & i[5] & !i[2]); assign out.pack = (!i[30] & !i[29] & i[27] & !i[25] & !i[13] & !i[12] & i[5] & i[4] & !i[2]); assign out.packu = (i[30] & i[27] & !i[13] & !i[12] & i[5] & i[4] & !i[2]); assign out.packh = (!i[30] & i[27] & !i[25] & i[13] & i[12] & !i[6] & i[5] & !i[2]); assign out.rol = (i[29] & !i[27] & !i[14] & i[12] & !i[6] & i[5] & i[4] & !i[2]); assign out.ror = (i[29] & !i[27] & i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.zbb = (!i[30]&!i[29]&i[27]&!i[24]&!i[23]&!i[22]&!i[21]&!i[20]&!i[13] &!i[12]&i[5]&i[4]&!i[2]) | (i[29]&!i[27]&!i[24]&!i[13]&i[12]&!i[5] &i[4]&!i[2]) | (i[29]&!i[27]&i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]) | ( i[30]&!i[27]&i[14]&!i[12]&!i[6]&i[5]&!i[2]) | (i[30]&!i[27]&i[13] &!i[6]&i[5]&i[4]&!i[2]) | (i[29]&!i[27]&i[12]&!i[6]&i[5]&i[4]&!i[2]) | ( !i[30]&i[29]&!i[24]&!i[23]&i[22]&i[21]&i[20]&i[14]&!i[13]&i[12]&!i[5] &i[4]&!i[2]) | (i[30]&i[29]&i[24]&i[23]&!i[22]&!i[21]&!i[20]&i[14] &!i[13]&i[12]&!i[5]&i[4]&!i[2]) | (i[27]&i[25]&i[14]&!i[6]&i[5]&!i[2]); assign out.bset = (!i[30] & i[29] & !i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.bclr = (i[30] & !i[29] & !i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.binv = (i[30] & i[29] & i[27] & !i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.bext = (i[30] & !i[29] & i[27] & i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.zbs = (i[29]&i[27]&!i[14]&!i[13]&i[12]&!i[6]&i[4]&!i[2]) | (i[30]&!i[29] &i[27]&!i[13]&i[12]&!i[6]&i[4]&!i[2]); assign out.bcompress = (!i[30]&!i[29]&i[27]&!i[25]&i[13]&!i[12]&!i[6]&i[5]&i[4]&!i[2]); assign out.bdecompress = (i[30] & i[27] & i[13] & !i[12] & !i[6] & i[5] & i[4] & !i[2]); assign out.zbe = (i[30]&i[27]&i[14]&i[13]&!i[12]&!i[6]&i[5]&!i[2]) | (!i[30]&i[27] &!i[25]&i[13]&i[12]&!i[6]&i[5]&!i[2]) | (!i[30]&!i[29]&i[27]&!i[25] &!i[12]&!i[6]&i[5]&i[4]&!i[2]); assign out.clmul = (i[27] & i[25] & !i[14] & !i[13] & !i[6] & i[5] & i[4] & !i[2]); assign out.clmulh = (i[27] & !i[14] & i[13] & i[12] & !i[6] & i[5] & !i[2]); assign out.clmulr = (i[27] & i[25] & !i[14] & !i[12] & !i[6] & i[5] & i[4] & !i[2]); assign out.zbc = (i[27] & i[25] & !i[14] & !i[6] & i[5] & i[4] & !i[2]); assign out.grev = (i[30] & i[29] & i[27] & i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.gorc = (!i[30] & i[29] & i[14] & !i[13] & i[12] & !i[6] & i[4] & !i[2]); assign out.shfl = (!i[30]&!i[29]&i[27]&!i[25]&!i[14]&!i[13]&i[12]&!i[6]&i[4]&!i[2]); assign out.unshfl = (!i[30]&!i[29]&i[27]&!i[25]&i[14]&!i[13]&i[12]&!i[6]&i[4]&!i[2]); assign out.xperm_n = (i[29] & i[27] & !i[14] & !i[12] & !i[6] & i[5] & i[4] & !i[2]); assign out.xperm_b = (i[29] & i[27] & !i[13] & !i[12] & i[5] & i[4] & !i[2]); assign out.xperm_h = (i[29] & i[27] & i[14] & i[13] & !i[6] & i[5] & !i[2]); assign out.zbp = (i[30]&!i[27]&!i[14]&i[12]&!i[6]&i[5]&i[4]&!i[2]) | (!i[30]&i[27] &!i[25]&i[13]&i[12]&!i[6]&i[5]&!i[2]) | (i[30]&!i[27]&i[13]&!i[6] &i[5]&i[4]&!i[2]) | (i[27]&!i[25]&!i[13]&!i[12]&i[5]&i[4]&!i[2]) | ( i[30]&i[14]&!i[13]&!i[12]&i[5]&i[4]&!i[2]) | (i[29]&i[27]&!i[12]&!i[6] &i[5]&i[4]&!i[2]) | (!i[30]&!i[29]&i[27]&!i[25]&!i[13]&i[12]&!i[6] &i[4]&!i[2]) | (i[29]&i[14]&!i[13]&i[12]&!i[6]&i[4]&!i[2]); assign out.crc32_b = (i[29]&!i[27]&i[24]&!i[23]&!i[21]&!i[20]&!i[14]&!i[13]&i[12] &!i[5]&i[4]&!i[2]); assign out.crc32_h = (i[29]&!i[27]&i[24]&!i[23]&i[20]&!i[14]&!i[13]&i[12]&!i[5]&i[4] &!i[2]); assign out.crc32_w = (i[29]&!i[27]&i[24]&!i[23]&i[21]&!i[14]&!i[13]&i[12]&!i[5]&i[4] &!i[2]); assign out.crc32c_b = (i[29]&!i[27]&i[23]&!i[21]&!i[20]&!i[14]&!i[13]&i[12]&!i[5] &i[4]&!i[2]); assign out.crc32c_h = (i[29]&!i[27]&i[23]&i[20]&!i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]); assign out.crc32c_w = (i[29]&!i[27]&i[23]&i[21]&!i[14]&!i[13]&i[12]&!i[5]&i[4]&!i[2]); assign out.zbr = (i[29] & !i[27] & i[24] & !i[14] & !i[13] & i[12] & !i[5] & i[4] & !i[2]); assign out.bfp = (i[30] & i[27] & i[13] & i[12] & !i[6] & i[5] & !i[2]); assign out.zbf = (!i[30]&!i[29]&i[27]&!i[25]&!i[13]&!i[12]&i[5]&i[4]&!i[2]) | ( i[27]&!i[25]&i[13]&i[12]&!i[6]&i[5]&!i[2]); assign out.sh1add = (i[29] & !i[27] & !i[14] & !i[12] & !i[6] & i[5] & i[4] & !i[2]); assign out.sh2add = (i[29] & !i[27] & i[14] & !i[13] & !i[12] & i[5] & i[4] & !i[2]); assign out.sh3add = (i[29] & !i[27] & i[14] & i[13] & !i[6] & i[5] & !i[2]); assign out.zba = (i[29] & !i[27] & !i[12] & !i[6] & i[5] & i[4] & !i[2]); assign out.pm_alu = (i[28]&i[20]&!i[13]&!i[12]&i[4]) | (!i[30]&!i[29]&!i[27]&!i[25] &!i[6]&i[4]) | (!i[29]&!i[27]&!i[25]&!i[13]&i[12]&!i[6]&i[4]) | ( !i[29]&!i[27]&!i[25]&!i[14]&!i[6]&i[4]) | (i[13]&!i[5]&i[4]) | (i[4] &i[2]) | (!i[12]&!i[5]&i[4]); assign out.legal = (!i[31]&!i[30]&i[29]&i[28]&!i[27]&!i[26]&!i[25]&!i[24]&!i[23] &!i[22]&i[21]&!i[20]&!i[19]&!i[18]&!i[17]&!i[16]&!i[15]&!i[14]&!i[11] &!i[10]&!i[9]&!i[8]&!i[7]&i[6]&i[5]&i[4]&!i[3]&!i[2]&i[1]&i[0]) | ( !i[31]&!i[30]&!i[29]&i[28]&!i[27]&!i[26]&!i[25]&!i[24]&!i[23]&i[22] &!i[21]&i[20]&!i[19]&!i[18]&!i[17]&!i[16]&!i[15]&!i[14]&!i[11]&!i[10] &!i[9]&!i[8]&!i[7]&i[6]&i[5]&i[4]&!i[3]&!i[2]&i[1]&i[0]) | (!i[31] &!i[30]&!i[29]&!i[28]&!i[27]&!i[26]&!i[25]&!i[24]&!i[23]&!i[22]&!i[21] &!i[19]&!i[18]&!i[17]&!i[16]&!i[15]&!i[14]&!i[11]&!i[10]&!i[9]&!i[8] &!i[7]&i[5]&i[4]&!i[3]&!i[2]&i[1]&i[0]) | (!i[31]&i[30]&i[29]&!i[28] &!i[26]&!i[25]&i[24]&!i[22]&!i[20]&!i[6]&!i[5]&i[4]&!i[3]&i[1]&i[0]) | ( !i[31]&i[30]&i[29]&!i[28]&!i[26]&!i[25]&i[24]&!i[22]&!i[21]&!i[6] &!i[5]&i[4]&!i[3]&i[1]&i[0]) | (!i[31]&i[30]&i[29]&!i[28]&!i[26] &!i[25]&!i[23]&!i[22]&!i[20]&!i[6]&!i[5]&i[4]&!i[3]&i[1]&i[0]) | ( !i[31]&i[30]&i[29]&!i[28]&!i[26]&!i[25]&!i[24]&!i[23]&!i[21]&!i[6] &!i[5]&i[4]&!i[3]&i[1]&i[0]) | (!i[31]&!i[30]&!i[29]&!i[28]&!i[26] &i[25]&i[13]&!i[6]&i[4]&!i[3]&i[1]&i[0]) | (!i[31]&!i[28]&i[27]&!i[26] &!i[25]&!i[24]&!i[6]&!i[5]&i[4]&!i[3]&i[1]&i[0]) | (!i[31]&!i[30] &i[29]&!i[28]&!i[26]&!i[25]&i[13]&!i[12]&!i[6]&i[4]&!i[3]&i[1]&i[0]) | ( !i[31]&!i[29]&!i[28]&!i[27]&!i[26]&!i[25]&!i[13]&!i[12]&!i[6]&i[4] &!i[3]&i[1]&i[0]) | (!i[31]&i[30]&!i[28]&!i[26]&!i[25]&i[14]&!i[6] &!i[5]&i[4]&!i[3]&i[1]&i[0]) | (!i[31]&!i[30]&!i[29]&!i[28]&!i[26] &!i[13]&i[12]&i[5]&i[4]&!i[3]&!i[2]&i[1]&i[0]) | (!i[31]&!i[30]&!i[29] &!i[28]&!i[27]&!i[26]&!i[25]&!i[6]&i[4]&!i[3]&i[1]&i[0]) | (!i[31] &i[30]&i[29]&!i[28]&!i[26]&!i[25]&!i[13]&i[12]&i[5]&i[4]&!i[3]&!i[2] &i[1]&i[0]) | (!i[31]&i[30]&!i[28]&i[27]&!i[26]&!i[25]&!i[13]&i[12] &!i[6]&i[4]&!i[3]&i[1]&i[0]) | (!i[31]&!i[29]&!i[28]&!i[26]&!i[25] &i[14]&!i[6]&i[5]&i[4]&!i[3]&i[1]&i[0]) | (!i[31]&i[29]&!i[28]&i[27] &!i[26]&!i[25]&!i[13]&i[12]&!i[6]&i[4]&!i[3]&i[1]&i[0]) | (!i[31] &!i[30]&!i[29]&!i[28]&!i[27]&!i[26]&!i[6]&i[5]&i[4]&!i[3]&i[1]&i[0]) | ( !i[31]&!i[30]&!i[29]&!i[28]&!i[26]&i[14]&!i[6]&i[5]&i[4]&!i[3]&i[1] &i[0]) | (!i[14]&!i[13]&!i[12]&i[6]&i[5]&!i[4]&!i[3]&i[1]&i[0]) | ( i[14]&i[6]&i[5]&!i[4]&!i[3]&!i[2]&i[1]&i[0]) | (!i[14]&!i[13]&i[5] &!i[4]&!i[3]&!i[2]&i[1]&i[0]) | (!i[12]&!i[6]&!i[5]&i[4]&!i[3]&i[1] &i[0]) | (!i[13]&i[12]&i[6]&i[5]&!i[3]&!i[2]&i[1]&i[0]) | (i[13]&i[6] &i[5]&i[4]&!i[3]&!i[2]&i[1]&i[0]) | (!i[30]&!i[29]&!i[28]&!i[14] &!i[13]&!i[6]&!i[5]&!i[4]&i[3]&i[2]&i[1]&i[0]) | (!i[31]&!i[30]&!i[28] &!i[26]&!i[25]&i[14]&!i[12]&!i[6]&i[4]&!i[3]&i[1]&i[0]) | (!i[14] &!i[13]&i[12]&!i[6]&!i[5]&!i[4]&i[3]&i[2]&i[1]&i[0]) | (i[6]&i[5] &!i[4]&i[3]&i[2]&i[1]&i[0]) | (!i[14]&!i[12]&!i[6]&!i[4]&!i[3]&!i[2] &i[1]&i[0]) | (!i[13]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]&i[0]) | ( i[13]&!i[6]&!i[5]&i[4]&!i[3]&i[1]&i[0]) | (!i[6]&i[4]&!i[3]&i[2]&i[1] &i[0]); endmodule // el2_dec_dec_ctl ================================================ FILE: design/dec/el2_dec_gpr_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_dec_gpr_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic [4:0] raddr0, // logical read addresses input logic [4:0] raddr1, input logic wen0, // write enable input logic [4:0] waddr0, // write address input logic [31:0] wd0, // write data input logic wen1, // write enable input logic [4:0] waddr1, // write address input logic [31:0] wd1, // write data input logic wen2, // write enable input logic [4:0] waddr2, // write address input logic [31:0] wd2, // write data input logic clk, input logic rst_l, output logic [31:0] rd0, // read data output logic [31:0] rd1, `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_regfile_if.veer_gpr_rf regfile, `endif // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); logic [31:1] [31:0] gpr_out; // 31 x 32 bit GPRs logic [31:1] [31:0] gpr_in; logic [31:1] w0v,w1v,w2v; logic [31:1] gpr_wr_en; `ifdef RV_LOCKSTEP_REGFILE_ENABLE assign regfile.gpr.ra = gpr_out[1][31:0]; // x1 assign regfile.gpr.sp = gpr_out[2][31:0]; // x2 assign regfile.gpr.fp = gpr_out[8][31:0]; // x8 assign regfile.gpr.a0 = gpr_out[10][31:0]; // x10 assign regfile.gpr.a1 = gpr_out[11][31:0]; // x11 assign regfile.gpr.a2 = gpr_out[12][31:0]; // x12 assign regfile.gpr.a3 = gpr_out[13][31:0]; // x13 assign regfile.gpr.a4 = gpr_out[14][31:0]; // x14 assign regfile.gpr.a5 = gpr_out[15][31:0]; // x15 assign regfile.gpr.a6 = gpr_out[16][31:0]; // x16 assign regfile.gpr.a7 = gpr_out[17][31:0]; // x17 `endif // GPR Write Enables assign gpr_wr_en[31:1] = (w0v[31:1] | w1v[31:1] | w2v[31:1]); for ( genvar j=1; j<32; j++ ) begin : gpr rvdffe #(32) gprff (.*, .en(gpr_wr_en[j]), .din(gpr_in[j][31:0]), .dout(gpr_out[j][31:0])); end : gpr // the read out always_comb begin rd0[31:0] = 32'b0; rd1[31:0] = 32'b0; w0v[31:1] = 31'b0; w1v[31:1] = 31'b0; w2v[31:1] = 31'b0; gpr_in[31:1] = '0; // GPR Read logic for (int j=1; j<32; j++ ) begin rd0[31:0] |= ({32{(raddr0[4:0]== 5'(j))}} & gpr_out[j][31:0]); rd1[31:0] |= ({32{(raddr1[4:0]== 5'(j))}} & gpr_out[j][31:0]); end // GPR Write logic for (int j=1; j<32; j++ ) begin w0v[j] = wen0 & (waddr0[4:0]== 5'(j) ); w1v[j] = wen1 & (waddr1[4:0]== 5'(j) ); w2v[j] = wen2 & (waddr2[4:0]== 5'(j) ); gpr_in[j] = ({32{w0v[j]}} & wd0[31:0]) | ({32{w1v[j]}} & wd1[31:0]) | ({32{w2v[j]}} & wd2[31:0]); end end // always_comb begin `ifdef RV_ASSERT_ON logic write_collision_unused; assign write_collision_unused = ( (w0v[31:1] == w1v[31:1]) & wen0 & wen1 ) | ( (w0v[31:1] == w2v[31:1]) & wen0 & wen2 ) | ( (w1v[31:1] == w2v[31:1]) & wen1 & wen2 ); // asserting that no 2 ports will write to the same gpr simultaneously assert_multiple_wen_to_same_gpr: assert #0 (~( write_collision_unused ) ); `endif endmodule ================================================ FILE: design/dec/el2_dec_ib_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_dec_ib_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic dbg_cmd_valid, // valid dbg cmd input logic dbg_cmd_write, // dbg cmd is write input logic [1:0] dbg_cmd_type, // dbg type input logic [31:0] dbg_cmd_addr, // expand to 31:0 input el2_br_pkt_t i0_brp, // i0 branch packet from aligner input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index input logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR input logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag input logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index input logic ifu_i0_pc4, // i0 is 4B inst else 2B input logic ifu_i0_valid, // i0 valid from ifu input logic ifu_i0_icaf, // i0 instruction access fault input logic [1:0] ifu_i0_icaf_type, // i0 instruction access fault type input logic ifu_i0_icaf_second, // i0 has access fault on second 2B of 4B inst input logic ifu_i0_dbecc, // i0 double-bit error input logic [31:0] ifu_i0_instr, // i0 instruction from the aligner input logic [31:1] ifu_i0_pc, // i0 pc from the aligner output logic dec_ib0_valid_d, // ib0 valid output logic dec_debug_valid_d, // Debug read or write at D-stage output logic [31:0] dec_i0_instr_d, // i0 inst at decode output logic [31:1] dec_i0_pc_d, // i0 pc at decode output logic dec_i0_pc4_d, // i0 is 4B inst else 2B output el2_br_pkt_t dec_i0_brp, // i0 branch packet at decode output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] dec_i0_bp_index, // i0 branch index output logic [pt.BHT_GHR_SIZE-1:0] dec_i0_bp_fghr, // BP FGHR output logic [pt.BTB_BTAG_SIZE-1:0] dec_i0_bp_btag, // BP tag output logic [$clog2(pt.BTB_SIZE)-1:0] dec_i0_bp_fa_index, // Fully associt btb index output logic dec_i0_icaf_d, // i0 instruction access fault at decode output logic dec_i0_icaf_second_d, // i0 instruction access fault on second 2B of 4B inst output logic [1:0] dec_i0_icaf_type_d, // i0 instruction access fault type output logic dec_i0_dbecc_d, // i0 double-bit error at decode output logic dec_debug_wdata_rs1_d, // put debug write data onto rs1 source: machine is halted output logic dec_debug_fence_d // debug fence inst ); logic debug_valid; logic [4:0] dreg; logic [11:0] dcsr; logic [31:0] ib0, ib0_debug_in; logic debug_read; logic debug_write; logic debug_read_gpr; logic debug_write_gpr; logic debug_read_csr; logic debug_write_csr; logic [34:0] ifu_i0_pcdata, pc0; assign ifu_i0_pcdata[34:0] = { ifu_i0_icaf_second, ifu_i0_dbecc, ifu_i0_icaf, ifu_i0_pc[31:1], ifu_i0_pc4 }; assign pc0[34:0] = ifu_i0_pcdata[34:0]; assign dec_i0_icaf_second_d = pc0[34]; // icaf's can only decode as i0 assign dec_i0_dbecc_d = pc0[33]; assign dec_i0_icaf_d = pc0[32]; assign dec_i0_pc_d[31:1] = pc0[31:1]; assign dec_i0_pc4_d = pc0[0]; assign dec_i0_icaf_type_d[1:0] = ifu_i0_icaf_type[1:0]; // GPR accesses // put reg to read on rs1 // read -> or %x0, %reg,%x0 {000000000000,reg[4:0],110000000110011} // put write date on rs1 // write -> or %reg, %x0, %x0 {00000000000000000110,reg[4:0],0110011} // CSR accesses // csr is of form rd, csr, rs1 // read -> csrrs %x0, %csr, %x0 {csr[11:0],00000010000001110011} // put write data on rs1 // write -> csrrw %x0, %csr, %x0 {csr[11:0],00000001000001110011} // abstract memory command not done here assign debug_valid = dbg_cmd_valid & (dbg_cmd_type[1:0] != 2'h2); assign debug_read = debug_valid & ~dbg_cmd_write; assign debug_write = debug_valid & dbg_cmd_write; assign debug_read_gpr = debug_read & (dbg_cmd_type[1:0]==2'h0); assign debug_write_gpr = debug_write & (dbg_cmd_type[1:0]==2'h0); assign debug_read_csr = debug_read & (dbg_cmd_type[1:0]==2'h1); assign debug_write_csr = debug_write & (dbg_cmd_type[1:0]==2'h1); assign dreg[4:0] = dbg_cmd_addr[4:0]; assign dcsr[11:0] = dbg_cmd_addr[11:0]; assign ib0_debug_in[31:0] = ({32{debug_read_gpr}} & {12'b000000000000,dreg[4:0],15'b110000000110011}) | ({32{debug_write_gpr}} & {20'b00000000000000000110,dreg[4:0],7'b0110011}) | ({32{debug_read_csr}} & {dcsr[11:0],20'b00000010000001110011}) | ({32{debug_write_csr}} & {dcsr[11:0],20'b00000001000001110011}); // machine is in halted state, pipe empty, write will always happen next cycle assign dec_debug_wdata_rs1_d = debug_write_gpr | debug_write_csr; // special fence csr for use only in debug mode assign dec_debug_fence_d = debug_write_csr & (dcsr[11:0] == 12'h7c4); assign ib0[31:0] = (debug_valid) ? ib0_debug_in[31:0] : ifu_i0_instr[31:0]; assign dec_ib0_valid_d = ifu_i0_valid | debug_valid; assign dec_debug_valid_d = debug_valid; assign dec_i0_instr_d[31:0] = ib0[31:0]; assign dec_i0_brp = i0_brp; assign dec_i0_bp_index = ifu_i0_bp_index; assign dec_i0_bp_fghr = ifu_i0_bp_fghr; assign dec_i0_bp_btag = ifu_i0_bp_btag; assign dec_i0_bp_fa_index = ifu_i0_fa_index; endmodule ================================================ FILE: design/dec/el2_dec_pmp_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2023 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // el2_dec_pmp_ctl.sv // // // Function: Physical Memory Protection CSRs // Comments: // //******************************************************************************** module el2_dec_pmp_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic free_l2clk, input logic csr_wr_clk, input logic rst_l, input logic dec_csr_wen_r_mod, // csr write enable at wb input logic [11:0] dec_csr_wraddr_r, // write address for csr input logic [31:0] dec_csr_wrdata_r, // csr write data at wb input logic [11:0] dec_csr_rdaddr_d, // read address for csr input logic csr_pmpcfg, input logic csr_pmpaddr0, input logic csr_pmpaddr16, input logic csr_pmpaddr32, input logic csr_pmpaddr48, input logic dec_pause_state, // Paused input logic dec_tlu_pmu_fw_halted, // pmu/fw halted input logic internal_dbg_halt_timers, // debug halted `ifdef RV_SMEPMP input el2_mseccfg_pkt_t mseccfg, `endif output logic [31:0] dec_pmp_rddata_d, // pmp CSR read data output logic dec_pmp_read_d, // pmp CSR address match output el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES], output logic [31:0] pmp_pmpaddr [pt.PMP_ENTRIES], // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); logic wr_pmpcfg_r; logic [3:0] wr_pmpcfg_group; logic wr_pmpaddr0_sel; logic wr_pmpaddr16_sel; logic wr_pmpaddr32_sel; logic wr_pmpaddr48_sel; logic wr_pmpaddr_r; logic [1:0] wr_pmpaddr_quarter; logic [5:0] wr_pmpaddr_address; logic [3:0] pmp_quarter_rdaddr; logic [31:0] pmp_pmpcfg_rddata; // ---------------------------------------------------------------------- logic [pt.PMP_ENTRIES-1:0] entry_lock_eff; // Effective entry lock for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_pmpcfg_lock `ifdef RV_SMEPMP // Smepmp allow modifying locked entries when mseccfg.RLB is set assign entry_lock_eff[r] = pmp_pmpcfg[r].lock & ~mseccfg.RLB; `else assign entry_lock_eff[r] = pmp_pmpcfg[r].lock; `endif end // ---------------------------------------------------------------------- // PMPCFGx (RW) // [31:24] : PMP entry (x*4 + 3) configuration // [23:16] : PMP entry (x*4 + 2) configuration // [15:8] : PMP entry (x*4 + 1) configuration // [7:0] : PMP entry (x*4 + 0) configuration localparam PMPCFG = 12'h3a0; localparam PMP_ENTRIES_WIDTH = $clog2(pt.PMP_ENTRIES); assign wr_pmpcfg_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:4] == PMPCFG[11:4]); assign wr_pmpcfg_group = dec_csr_wraddr_r[3:0]; // selects group of 4 pmpcfg entries (group 1 -> entries 4-7; up to 16 groups) for (genvar entry_idx = 0; entry_idx < pt.PMP_ENTRIES; entry_idx++) begin : gen_pmpcfg_ff logic [7:0] raw_wdata; logic [7:0] csr_wdata; // PMPCFG fields are WARL. Mask out bits 6:5 during write. // When Smepmp is disabled R=0 and W=1 combination is illegal mask out W // when R is cleared. assign raw_wdata = dec_csr_wrdata_r[(entry_idx[1:0]*8)+7:(entry_idx[1:0]*8)+0]; `ifdef RV_SMEPMP assign csr_wdata = raw_wdata & 8'b10011111; `else assign csr_wdata = raw_wdata[0] ? (raw_wdata & 8'b10011111) : (raw_wdata & 8'b10011101); `endif rvdffe #(8) pmpcfg_ff (.*, .clk(free_l2clk), .en(wr_pmpcfg_r & (wr_pmpcfg_group == entry_idx[5:2]) & (~entry_lock_eff[entry_idx])), .din(csr_wdata), .dout(pmp_pmpcfg[entry_idx])); end // ---------------------------------------------------------------------- // PMPADDRx (RW) // [31:0] : PMP entry (x) address selector (word addressing) // // NOTE: VeeR-EL2 uses 32-bit physical addressing, register bits 31:30 mapping // to bits 33:32 of the physical address are always set to 0. (WARL) localparam PMPADDR0 = 12'h3b0; localparam PMPADDR16 = 12'h3c0; localparam PMPADDR32 = 12'h3d0; localparam PMPADDR48 = 12'h3e0; assign wr_pmpaddr0_sel = dec_csr_wraddr_r[11:4] == PMPADDR0[11:4]; assign wr_pmpaddr16_sel = dec_csr_wraddr_r[11:4] == PMPADDR16[11:4]; assign wr_pmpaddr32_sel = dec_csr_wraddr_r[11:4] == PMPADDR32[11:4]; assign wr_pmpaddr48_sel = dec_csr_wraddr_r[11:4] == PMPADDR48[11:4]; assign wr_pmpaddr_r = dec_csr_wen_r_mod & (wr_pmpaddr0_sel | wr_pmpaddr16_sel | wr_pmpaddr32_sel | wr_pmpaddr48_sel); assign wr_pmpaddr_quarter[0] = wr_pmpaddr16_sel | wr_pmpaddr48_sel; assign wr_pmpaddr_quarter[1] = wr_pmpaddr32_sel | wr_pmpaddr48_sel; assign wr_pmpaddr_address = {wr_pmpaddr_quarter, dec_csr_wraddr_r[3:0]}; // entry address for (genvar entry_idx = 0; entry_idx < pt.PMP_ENTRIES; entry_idx++) begin : gen_pmpaddr_ff logic pmpaddr_lock; logic pmpaddr_lock_next; if (entry_idx+1 < pt.PMP_ENTRIES) assign pmpaddr_lock_next = entry_lock_eff[entry_idx+1] & pmp_pmpcfg[entry_idx+1].mode == TOR; else assign pmpaddr_lock_next = 1'b0; assign pmpaddr_lock = entry_lock_eff[entry_idx] | pmpaddr_lock_next; assign pmp_pmpaddr[entry_idx][31:30] = 2'b00; rvdffe #(30) pmpaddr_ff (.*, .clk(free_l2clk), .en(wr_pmpaddr_r & (wr_pmpaddr_address == entry_idx) & (~pmpaddr_lock)), .din(dec_csr_wrdata_r[29:0]), .dout(pmp_pmpaddr[entry_idx][29:0])); end // CSR read mux logic [5:0] pmp_pmpcfg_rdata_selector [4]; logic [5:0] dec_pmp_rdata_selector [4]; assign pmp_quarter_rdaddr = dec_csr_rdaddr_d[3:0]; for (genvar i = 0; i < 4; i++) begin: gen_csr_selector assign pmp_pmpcfg_rdata_selector[i] = {pmp_quarter_rdaddr, 2'(i)}; assign dec_pmp_rdata_selector[i] = {2'(i), pmp_quarter_rdaddr}; end assign pmp_pmpcfg_rddata = { pmp_pmpcfg[pmp_pmpcfg_rdata_selector[3][PMP_ENTRIES_WIDTH-1:0]], pmp_pmpcfg[pmp_pmpcfg_rdata_selector[2][PMP_ENTRIES_WIDTH-1:0]], pmp_pmpcfg[pmp_pmpcfg_rdata_selector[1][PMP_ENTRIES_WIDTH-1:0]], pmp_pmpcfg[pmp_pmpcfg_rdata_selector[0][PMP_ENTRIES_WIDTH-1:0]] }; assign dec_pmp_read_d = csr_pmpcfg | csr_pmpaddr0 | csr_pmpaddr16 | csr_pmpaddr32 | csr_pmpaddr48; assign dec_pmp_rddata_d[31:0] = ( ({32{csr_pmpcfg}} & pmp_pmpcfg_rddata) | ({32{csr_pmpaddr0}} & pmp_pmpaddr[dec_pmp_rdata_selector[0][PMP_ENTRIES_WIDTH-1:0]]) | ({32{csr_pmpaddr16}} & pmp_pmpaddr[dec_pmp_rdata_selector[1][PMP_ENTRIES_WIDTH-1:0]]) | ({32{csr_pmpaddr32}} & pmp_pmpaddr[dec_pmp_rdata_selector[2][PMP_ENTRIES_WIDTH-1:0]]) | ({32{csr_pmpaddr48}} & pmp_pmpaddr[dec_pmp_rdata_selector[3][PMP_ENTRIES_WIDTH-1:0]]) ); endmodule // dec_pmp_ctl ================================================ FILE: design/dec/el2_dec_tlu_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or it's affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // el2_dec_tlu_ctl.sv // // // Function: CSRs, Commit/WB, flushing, exceptions, interrupts // Comments: // //******************************************************************************** module el2_dec_tlu_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic free_clk, input logic free_l2clk, input logic rst_l, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ //rst_vec is supposed to be connected to constant in the top level /*pragma coverage off*/ input logic [31:1] rst_vec, // reset vector, from core pins /*pragma coverage on*/ input logic nmi_int, // nmi pin //nmi_vec is supposed to be connected to constant in the top level /*pragma coverage off*/ input logic [31:1] nmi_vec, // nmi vector /*pragma coverage on*/ input logic i_cpu_halt_req, // Asynchronous Halt request to CPU input logic i_cpu_run_req, // Asynchronous Restart request to CPU input logic lsu_fastint_stall_any, // needed by lsu for 2nd pass of dma with ecc correction, stall next cycle // perf counter inputs input logic ifu_pmu_instr_aligned, // aligned instructions input logic ifu_pmu_fetch_stall, // fetch unit stalled input logic ifu_pmu_ic_miss, // icache miss input logic ifu_pmu_ic_hit, // icache hit input logic ifu_pmu_bus_error, // Instruction side bus error input logic ifu_pmu_bus_busy, // Instruction side bus busy input logic ifu_pmu_bus_trxn, // Instruction side bus transaction input logic dec_pmu_instr_decoded, // decoded instructions input logic dec_pmu_decode_stall, // decode stall input logic dec_pmu_presync_stall, // decode stall due to presync'd inst input logic dec_pmu_postsync_stall,// decode stall due to postsync'd inst input logic lsu_store_stall_any, // SB or WB is full, stall decode input logic dma_dccm_stall_any, // DMA stall of lsu input logic dma_iccm_stall_any, // DMA stall of ifu input logic exu_pmu_i0_br_misp, // pipe 0 branch misp input logic exu_pmu_i0_br_ataken, // pipe 0 branch actual taken input logic exu_pmu_i0_pc4, // pipe 0 4 byte branch input logic lsu_pmu_bus_trxn, // D side bus transaction input logic lsu_pmu_bus_misaligned, // D side bus misaligned input logic lsu_pmu_bus_error, // D side bus error input logic lsu_pmu_bus_busy, // D side bus busy input logic lsu_pmu_load_external_m, // D side bus load input logic lsu_pmu_store_external_m, // D side bus store input logic dma_pmu_dccm_read, // DMA DCCM read input logic dma_pmu_dccm_write, // DMA DCCM write input logic dma_pmu_any_read, // DMA read input logic dma_pmu_any_write, // DMA write input logic [31:1] lsu_fir_addr, // Fast int address input logic [1:0] lsu_fir_error, // Fast int lookup error input logic iccm_dma_sb_error, // I side dma single bit error input el2_lsu_error_pkt_t lsu_error_pkt_r, // lsu precise exception/error packet input logic lsu_single_ecc_error_incr, // LSU inc SB error counter input logic dec_pause_state, // Pause counter not zero input logic lsu_imprecise_error_store_any, // store bus error input logic lsu_imprecise_error_load_any, // store bus error input logic [31:0] lsu_imprecise_error_addr_any, // store bus error address input logic dec_csr_wen_unq_d, // valid csr with write - for csr legal input logic dec_csr_any_unq_d, // valid csr - for csr legal input logic [11:0] dec_csr_rdaddr_d, // read address for csr input logic dec_csr_wen_r, // csr write enable at wb input logic [11:0] dec_csr_rdaddr_r, // read address for csr input logic [11:0] dec_csr_wraddr_r, // write address for csr input logic [31:0] dec_csr_wrdata_r, // csr write data at wb input logic dec_csr_stall_int_ff, // csr is mie/mstatus input logic dec_tlu_i0_valid_r, // pipe 0 op at e4 is valid input logic [31:1] exu_npc_r, // for NPC tracking input logic [31:1] dec_tlu_i0_pc_r, // for PC/NPC tracking input el2_trap_pkt_t dec_tlu_packet_r, // exceptions known at decode input logic [31:0] dec_illegal_inst, // For mtval input logic dec_i0_decode_d, // decode valid, used for clean icache diagnostics // branch info from pipe0 for errors or counter updates input logic [1:0] exu_i0_br_hist_r, // history input logic exu_i0_br_error_r, // error input logic exu_i0_br_start_error_r, // start error input logic exu_i0_br_valid_r, // valid input logic exu_i0_br_mp_r, // mispredict input logic exu_i0_br_middle_r, // middle of bank // branch info from pipe1 for errors or counter updates input logic exu_i0_br_way_r, // way hit or repl output logic dec_tlu_core_empty, // core is empty // Debug start output logic dec_dbg_cmd_done, // abstract command done output logic dec_dbg_cmd_fail, // abstract command failed output logic dec_tlu_dbg_halted, // Core is halted and ready for debug command output logic dec_tlu_debug_mode, // Core is in debug mode output logic dec_tlu_resume_ack, // Resume acknowledge output logic dec_tlu_debug_stall, // stall decode while waiting on core to empty output logic dec_tlu_flush_noredir_r , // Tell fetch to idle on this flush output logic dec_tlu_mpc_halted_only, // Core is halted only due to MPC output logic dec_tlu_flush_leak_one_r, // single step output logic dec_tlu_flush_err_r, // iside perr/ecc rfpc. This is the D stage of the error output logic dec_tlu_flush_extint, // fast ext int started output logic [31:2] dec_tlu_meihap, // meihap for fast int input logic dbg_halt_req, // DM requests a halt input logic dbg_resume_req, // DM requests a resume input logic ifu_miss_state_idle, // I-side miss buffer empty input logic lsu_idle_any, // lsu is idle input logic dec_div_active, // oop div is active output el2_trigger_pkt_t [3:0] trigger_pkt_any, // trigger info for trigger blocks input logic ifu_ic_error_start, // IC single bit error input logic ifu_iccm_rd_ecc_single_err, // ICCM single bit error input logic [70:0] ifu_ic_debug_rd_data, // diagnostic icache read data input logic ifu_ic_debug_rd_data_valid, // diagnostic icache read data valid output el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt, // packet of DICAWICS, DICAD0/1, DICAGO info for icache diagnostics // Debug end input logic [7:0] pic_claimid, // pic claimid for csr input logic [3:0] pic_pl, // pic priv level for csr input logic mhwakeup, // high priority external int, wakeup if halted input logic mexintpend, // external interrupt pending input logic timer_int, // timer interrupt pending input logic soft_int, // software interrupt pending output logic o_cpu_halt_status, // PMU interface, halted output logic o_cpu_halt_ack, // halt req ack output logic o_cpu_run_ack, // run req ack output logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request /*pragma coverage off*/ input logic [31:4] core_id, // Core ID /*pragma coverage on*/ // external MPC halt/run interface input logic mpc_debug_halt_req, // Async halt request input logic mpc_debug_run_req, // Async run request input logic mpc_reset_run_req, // Run/halt after reset output logic mpc_debug_halt_ack, // Halt ack output logic mpc_debug_run_ack, // Run ack output logic debug_brkpt_status, // debug breakpoint output logic [3:0] dec_tlu_meicurpl, // to PIC output logic [3:0] dec_tlu_meipt, // to PIC output logic [31:0] dec_csr_rddata_d, // csr read data at wb output logic dec_csr_legal_d, // csr indicates legal operation output el2_br_tlu_pkt_t dec_tlu_br0_r_pkt, // branch pkt to bp output logic dec_tlu_i0_kill_writeb_wb, // I0 is flushed, don't writeback any results to arch state output logic dec_tlu_flush_lower_wb, // commit has a flush (exception, int, mispredict at e4) output logic dec_tlu_i0_commit_cmt, // committed an instruction output logic dec_tlu_i0_kill_writeb_r, // I0 is flushed, don't writeback any results to arch state output logic dec_tlu_flush_lower_r, // commit has a flush (exception, int) output logic [31:1] dec_tlu_flush_path_r, // flush pc output logic dec_tlu_fence_i_r, // flush is a fence_i rfnpc, flush icache output logic dec_tlu_wr_pause_r, // CSR write to pause reg is at R. output logic dec_tlu_flush_pause_r, // Flush is due to pause output logic dec_tlu_presync_d, // CSR read needs to be presync'd output logic dec_tlu_postsync_d, // CSR needs to be presync'd output logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control output logic dec_tlu_force_halt, // halt has been forced output logic dec_tlu_perfcnt0, // toggles when pipe0 perf counter 0 has an event inc output logic dec_tlu_perfcnt1, // toggles when pipe0 perf counter 1 has an event inc output logic dec_tlu_perfcnt2, // toggles when pipe0 perf counter 2 has an event inc output logic dec_tlu_perfcnt3, // toggles when pipe0 perf counter 3 has an event inc output logic dec_tlu_i0_exc_valid_wb1, // pipe 0 exception valid output logic dec_tlu_i0_valid_wb1, // pipe 0 valid output logic dec_tlu_int_valid_wb1, // pipe 2 int valid output logic [4:0] dec_tlu_exc_cause_wb1, // exception or int cause output logic [31:0] dec_tlu_mtval_wb1, // MTVAL value // feature disable from mfdc output logic dec_tlu_external_ldfwd_disable, // disable external load forwarding output logic dec_tlu_sideeffect_posted_disable, // disable posted stores to side-effect address output logic dec_tlu_core_ecc_disable, // disable core ECC output logic dec_tlu_bpred_disable, // disable branch prediction output logic dec_tlu_wb_coalescing_disable, // disable writebuffer coalescing output logic dec_tlu_pipelining_disable, // disable pipelining output logic dec_tlu_trace_disable, // disable trace output logic [2:0] dec_tlu_dma_qos_prty, // DMA QoS priority coming from MFDC [18:16] // clock gating overrides from mcgc output logic dec_tlu_misc_clk_override, // override misc clock domain gating output logic dec_tlu_dec_clk_override, // override decode clock domain gating output logic dec_tlu_ifu_clk_override, // override fetch clock domain gating output logic dec_tlu_lsu_clk_override, // override load/store clock domain gating output logic dec_tlu_bus_clk_override, // override bus clock domain gating output logic dec_tlu_pic_clk_override, // override PIC clock domain gating output logic dec_tlu_picio_clk_override,// override PICIO clock domain gating output logic dec_tlu_dccm_clk_override, // override DCCM clock domain gating output logic dec_tlu_icm_clk_override, // override ICCM clock domain gating `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_regfile_if.veer_tlu_rf regfile, `endif `ifdef RV_USER_MODE // Privilege mode // 0 - machine, 1 - user output logic priv_mode, output logic priv_mode_eff, output logic priv_mode_ns, // mseccfg CSR content for PMP output logic [2:0] mseccfg, `endif // pmp output el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES], output logic [31:0] pmp_pmpaddr [pt.PMP_ENTRIES] ); logic clk_override, e4e5_int_clk, nmi_fir_type, nmi_lsu_load_type, nmi_lsu_store_type, nmi_int_detected_f, nmi_lsu_load_type_f, nmi_lsu_store_type_f, allow_dbg_halt_csr_write, dbg_cmd_done_ns, i_cpu_run_req_d1_raw, debug_mode_status, lsu_single_ecc_error_r_d1, sel_npc_r, sel_npc_resume, ce_int, nmi_in_debug_mode, dpc_capture_npc, dpc_capture_pc, tdata_load, tdata_opcode, tdata_action, perfcnt_halted, tdata_chain, tdata_kill_write; logic reset_delayed, reset_detect, reset_detected; logic wr_mstatus_r, wr_mtvec_r, wr_mcyclel_r, wr_mcycleh_r, wr_minstretl_r, wr_minstreth_r, wr_mscratch_r, wr_mepc_r, wr_mcause_r, wr_mscause_r, wr_mtval_r, wr_mrac_r, wr_meihap_r, wr_meicurpl_r, wr_meipt_r, wr_dcsr_r, wr_dpc_r, wr_meicidpl_r, wr_meivt_r, wr_meicpct_r, wr_micect_r, wr_miccmect_r, wr_mfdht_r, wr_mfdhs_r, wr_mdccmect_r,wr_mhpme3_r, wr_mhpme4_r, wr_mhpme5_r, wr_mhpme6_r; logic wr_mpmc_r; logic [1:1] mpmc_b_ns, mpmc, mpmc_b; logic set_mie_pmu_fw_halt, fw_halted_ns, fw_halted; logic wr_mcountinhibit_r; `ifdef RV_USER_MODE logic wr_mcounteren_r; logic [5:0] mcounteren; // HPM6, HPM5, HPM4, HPM3, IR, CY logic wr_mseccfg_r; logic [2:0] mseccfg_ns; `endif logic [6:0] mcountinhibit; logic wr_mtsel_r, wr_mtdata1_t0_r, wr_mtdata1_t1_r, wr_mtdata1_t2_r, wr_mtdata1_t3_r, wr_mtdata2_t0_r, wr_mtdata2_t1_r, wr_mtdata2_t2_r, wr_mtdata2_t3_r; logic [31:0] mtdata2_t0, mtdata2_t1, mtdata2_t2, mtdata2_t3, mtdata2_tsel_out, mtdata1_tsel_out; logic [9:0] mtdata1_t0_ns, mtdata1_t0, mtdata1_t1_ns, mtdata1_t1, mtdata1_t2_ns, mtdata1_t2, mtdata1_t3_ns, mtdata1_t3; logic [9:0] tdata_wrdata_r; logic [1:0] mtsel_ns, mtsel; logic tlu_i0_kill_writeb_r; `ifdef RV_USER_MODE logic [3:0] mstatus_ns, mstatus; // MPRV, MPP (inverted! 0-M, 1-U), MPIE, MIE `else logic [1:0] mstatus_ns, mstatus; `endif logic [1:0] mfdhs_ns, mfdhs; logic [31:0] force_halt_ctr, force_halt_ctr_f; logic force_halt; logic [5:0] mfdht, mfdht_ns; logic mstatus_mie_ns; logic [30:0] mtvec_ns, mtvec; logic [15:2] dcsr_ns, dcsr; logic [5:0] mip_ns, mip; logic [5:0] mie_ns, mie; logic [31:0] mcyclel_ns, mcyclel; logic [31:0] mcycleh_ns, mcycleh; logic [31:0] minstretl_ns, minstretl; logic [31:0] minstreth_ns, minstreth; logic [31:0] micect_ns, micect, miccmect_ns, miccmect, mdccmect_ns, mdccmect; logic [26:0] micect_inc, miccmect_inc, mdccmect_inc; logic [31:0] mscratch; logic [31:0] mhpmc3, mhpmc3_ns, mhpmc4, mhpmc4_ns, mhpmc5, mhpmc5_ns, mhpmc6, mhpmc6_ns; logic [31:0] mhpmc3h, mhpmc3h_ns, mhpmc4h, mhpmc4h_ns, mhpmc5h, mhpmc5h_ns, mhpmc6h, mhpmc6h_ns; logic [9:0] mhpme3, mhpme4, mhpme5, mhpme6; logic [31:0] mrac; logic [9:2] meihap; logic [31:10] meivt; logic [3:0] meicurpl_ns, meicurpl; logic [3:0] meicidpl_ns, meicidpl; logic [3:0] meipt_ns, meipt; logic [31:0] mdseac; logic mdseac_locked_ns, mdseac_locked_f, mdseac_en, nmi_lsu_detected; logic [31:1] mepc_ns, mepc; logic [31:1] dpc_ns, dpc; logic [31:0] mcause_ns, mcause; logic [3:0] mscause_ns, mscause, mscause_type; logic [31:0] mtval_ns, mtval; logic dec_pause_state_f, dec_tlu_wr_pause_r_d1, pause_expired_r, pause_expired_wb; logic tlu_flush_lower_r, tlu_flush_lower_r_d1; logic [31:1] tlu_flush_path_r, tlu_flush_path_r_d1; logic i0_valid_wb; logic tlu_i0_commit_cmt; logic [31:1] vectored_path, interrupt_path; logic [16:0] dicawics_ns, dicawics; logic wr_dicawics_r, wr_dicad0_r, wr_dicad1_r, wr_dicad0h_r; logic [31:0] dicad0_ns, dicad0, dicad0h_ns, dicad0h; logic [6:0] dicad1_ns, dicad1_raw; logic [31:0] dicad1; logic ebreak_r, ebreak_to_debug_mode_r, ecall_r, illegal_r, mret_r, inst_acc_r, fence_i_r, ic_perr_r, iccm_sbecc_r, ebreak_to_debug_mode_r_d1, kill_ebreak_count_r, inst_acc_second_r; logic ce_int_ready, ext_int_ready, timer_int_ready, soft_int_ready, int_timer0_int_ready, int_timer1_int_ready, mhwakeup_ready, take_ext_int, take_ce_int, take_timer_int, take_soft_int, take_int_timer0_int, take_int_timer1_int, take_nmi, take_nmi_r_d1, int_timer0_int_possible, int_timer1_int_possible; logic i0_exception_valid_r, interrupt_valid_r, i0_exception_valid_r_d1, interrupt_valid_r_d1, exc_or_int_valid_r, exc_or_int_valid_r_d1, mdccme_ce_req, miccme_ce_req, mice_ce_req; logic synchronous_flush_r; logic [4:0] exc_cause_r, exc_cause_wb; logic mcyclel_cout, mcyclel_cout_f, mcyclela_cout; logic [31:0] mcyclel_inc; logic [31:0] mcycleh_inc; logic minstretl_cout, minstretl_cout_f, minstret_enable, minstretl_cout_ns, minstretl_couta; logic [31:0] minstretl_inc, minstretl_read; logic [31:0] minstreth_inc, minstreth_read; logic [31:1] pc_r, pc_r_d1, npc_r, npc_r_d1; logic valid_csr; logic rfpc_i0_r; logic lsu_i0_rfnpc_r; logic dec_tlu_br0_error_r, dec_tlu_br0_start_error_r, dec_tlu_br0_v_r; logic lsu_i0_exc_r, lsu_i0_exc_r_raw, lsu_exc_ma_r, lsu_exc_acc_r, lsu_exc_st_r, lsu_exc_valid_r, lsu_exc_valid_r_raw, lsu_exc_valid_r_d1, lsu_i0_exc_r_d1, block_interrupts; logic i0_trigger_eval_r; logic request_debug_mode_r, request_debug_mode_r_d1, request_debug_mode_done, request_debug_mode_done_f; logic take_halt, halt_taken, halt_taken_f, internal_dbg_halt_mode, dbg_tlu_halted_f, take_reset, dbg_tlu_halted, core_empty, lsu_idle_any_f, ifu_miss_state_idle_f, resume_ack_ns, debug_halt_req_f, debug_resume_req_f_raw, debug_resume_req_f, enter_debug_halt_req, dcsr_single_step_done, dcsr_single_step_done_f, debug_halt_req_d1, debug_halt_req_ns, dcsr_single_step_running, dcsr_single_step_running_f, internal_dbg_halt_timers; logic [3:0] i0_trigger_r, trigger_action, trigger_enabled, i0_trigger_chain_masked_r; logic i0_trigger_hit_r, i0_trigger_hit_raw_r, i0_trigger_action_r, trigger_hit_r_d1, mepc_trigger_hit_sel_pc_r; logic [3:0] update_hit_bit_r, i0_iside_trigger_has_pri_r,i0trigger_qual_r, i0_lsu_trigger_has_pri_r; logic cpu_halt_status, cpu_halt_ack, cpu_run_ack, ext_halt_pulse, i_cpu_halt_req_d1, i_cpu_run_req_d1; logic inst_acc_r_raw, trigger_hit_dmode_r, trigger_hit_dmode_r_d1; logic [9:0] mcgc, mcgc_ns, mcgc_int; logic [18:0] mfdc; logic i_cpu_halt_req_sync_qual, i_cpu_run_req_sync_qual, pmu_fw_halt_req_ns, pmu_fw_halt_req_f, int_timer_stalled, fw_halt_req, enter_pmu_fw_halt_req, pmu_fw_tlu_halted, pmu_fw_tlu_halted_f, internal_pmu_fw_halt_mode, internal_pmu_fw_halt_mode_f, int_timer0_int_hold, int_timer1_int_hold, int_timer0_int_hold_f, int_timer1_int_hold_f; logic nmi_int_delayed, nmi_int_detected; logic [3:0] trigger_execute, trigger_data, trigger_store; logic dec_tlu_pmu_fw_halted; logic mpc_run_state_ns, debug_brkpt_status_ns, mpc_debug_halt_ack_ns, mpc_debug_run_ack_ns, dbg_halt_state_ns, dbg_run_state_ns, dbg_halt_state_f, mpc_debug_halt_req_sync_f, mpc_debug_run_req_sync_f, mpc_halt_state_f, mpc_halt_state_ns, mpc_run_state_f, debug_brkpt_status_f, mpc_debug_halt_ack_f, mpc_debug_run_ack_f, dbg_run_state_f, mpc_debug_halt_req_sync_pulse, mpc_debug_run_req_sync_pulse, debug_brkpt_valid, debug_halt_req, debug_resume_req, dec_tlu_mpc_halted_only_ns; logic take_ext_int_start, ext_int_freeze, take_ext_int_start_d1, take_ext_int_start_d2, take_ext_int_start_d3, ext_int_freeze_d1, ignore_ext_int_due_to_lsu_stall; logic mcause_sel_nmi_store, mcause_sel_nmi_load, mcause_sel_nmi_ext, fast_int_meicpct; logic [1:0] mcause_fir_error_type; logic dbg_halt_req_held_ns, dbg_halt_req_held, dbg_halt_req_final; logic iccm_repair_state_ns, iccm_repair_state_d1, iccm_repair_state_rfnpc; // internal timer, isolated for size reasons logic [31:0] dec_timer_rddata_d; logic dec_timer_read_d, dec_timer_t0_pulse, dec_timer_t1_pulse; // PMP unit, isolated for size reasons logic [31:0] dec_pmp_rddata_d; logic dec_pmp_read_d; logic nmi_int_sync, timer_int_sync, soft_int_sync, i_cpu_halt_req_sync, i_cpu_run_req_sync, mpc_debug_halt_req_sync, mpc_debug_run_req_sync, mpc_debug_halt_req_sync_raw; logic csr_wr_clk; logic e4e5_clk, e4_valid, e5_valid, e4e5_valid, internal_dbg_halt_mode_f, internal_dbg_halt_mode_f2; logic lsu_pmu_load_external_r, lsu_pmu_store_external_r; logic dec_tlu_flush_noredir_r_d1, dec_tlu_flush_pause_r_d1; logic lsu_single_ecc_error_r; logic [31:0] lsu_error_pkt_addr_r; logic mcyclel_cout_in; logic i0_valid_no_ebreak_ecall_r; logic minstret_enable_f; logic sel_exu_npc_r, sel_flush_npc_r, sel_hold_npc_r; logic pc0_valid_r; logic [15:0] mfdc_int, mfdc_ns; logic [31:0] mrac_in; logic [31:27] csr_sat; logic [8:6] dcsr_cause; logic enter_debug_halt_req_le, dcsr_cause_upgradeable; logic icache_rd_valid, icache_wr_valid, icache_rd_valid_f, icache_wr_valid_f; logic [3:0] mhpmc_inc_r, mhpmc_inc_r_d1; logic [3:0][9:0] mhpme_vec; logic mhpmc3_wr_en0, mhpmc3_wr_en1, mhpmc3_wr_en; logic mhpmc4_wr_en0, mhpmc4_wr_en1, mhpmc4_wr_en; logic mhpmc5_wr_en0, mhpmc5_wr_en1, mhpmc5_wr_en; logic mhpmc6_wr_en0, mhpmc6_wr_en1, mhpmc6_wr_en; logic mhpmc3h_wr_en0, mhpmc3h_wr_en; logic mhpmc4h_wr_en0, mhpmc4h_wr_en; logic mhpmc5h_wr_en0, mhpmc5h_wr_en; logic mhpmc6h_wr_en0, mhpmc6h_wr_en; logic [63:0] mhpmc3_incr, mhpmc4_incr, mhpmc5_incr, mhpmc6_incr; logic perfcnt_halted_d1, zero_event_r; logic [3:0] perfcnt_during_sleep; logic [9:0] event_r; el2_inst_pkt_t pmu_i0_itype_qual; logic dec_csr_wen_r_mod; logic flush_clkvalid; logic sel_fir_addr; logic wr_mie_r; logic mtval_capture_pc_r; logic mtval_capture_pc_plus2_r; logic mtval_capture_inst_r; logic mtval_capture_lsu_r; logic mtval_clear_r; logic wr_mcgc_r; logic wr_mfdc_r; logic wr_mdeau_r; logic trigger_hit_for_dscr_cause_r_d1; logic conditionally_illegal; logic [3:0] ifu_mscause ; logic ifu_ic_error_start_f, ifu_iccm_rd_ecc_single_err_f; // CSR address decoder // files "csrdecode_m" (machine mode only) and "csrdecode_mu" (machine mode plus // user mode) are human readable that have all of the CSR decodes defined and // are part of the git repo. Modify these files as needed. // to generate all the equations below from "csrdecode" except legal equation: // 1) coredecode -in csrdecode > corecsrdecode.e // 2) espresso -Dso -oeqntott < corecsrdecode.e | addassign > csrequations // to generate the legal CSR equation below: // 1) coredecode -in csrdecode -legal > csrlegal.e // 2) espresso -Dso -oeqntott < csrlegal.e | addassign > csrlegal_equation // coredecode -in csrdecode > corecsrdecode.e; espresso -Dso -oeqntott < corecsrdecode.e | addassign > csrequations; coredecode -in csrdecode -legal > csrlegal.e; espresso -Dso -oeqntott csrlegal.e | addassign > csrlegal_equation `ifdef RV_USER_MODE `include "el2_dec_csr_equ_mu.svh" logic csr_acc_r; // CSR access error logic csr_wr_usr_r; // Write to an unprivileged/user-level CSR logic csr_rd_usr_r; // REad from an unprivileged/user-level CSR `else `include "el2_dec_csr_equ_m.svh" `endif el2_dec_timer_ctl #(.pt(pt)) int_timers(.*); // end of internal timers el2_dec_pmp_ctl #(.pt(pt)) pmp(.*); // end of pmp assign clk_override = dec_tlu_dec_clk_override; // Async inputs to the core have to be sync'd to the core clock. rvsyncss #(7) syncro_ff(.*, .clk(free_clk), .din ({nmi_int, timer_int, soft_int, i_cpu_halt_req, i_cpu_run_req, mpc_debug_halt_req, mpc_debug_run_req}), .dout({nmi_int_sync, timer_int_sync, soft_int_sync, i_cpu_halt_req_sync, i_cpu_run_req_sync, mpc_debug_halt_req_sync_raw, mpc_debug_run_req_sync})); // for CSRs that have inpipe writes only rvoclkhdr csrwr_r_cgc ( .en(dec_csr_wen_r_mod | clk_override), .l1clk(csr_wr_clk), .* ); assign e4_valid = dec_tlu_i0_valid_r; assign e4e5_valid = e4_valid | e5_valid; assign flush_clkvalid = internal_dbg_halt_mode_f | i_cpu_run_req_d1 | interrupt_valid_r | interrupt_valid_r_d1 | reset_delayed | pause_expired_r | pause_expired_wb | ic_perr_r | iccm_sbecc_r | clk_override; rvoclkhdr e4e5_cgc ( .en(e4e5_valid | clk_override), .l1clk(e4e5_clk), .* ); rvoclkhdr e4e5_int_cgc ( .en(e4e5_valid | flush_clkvalid), .l1clk(e4e5_int_clk), .* ); rvdffie #(11) freeff (.*, .clk(free_l2clk), .din ({ifu_ic_error_start, ifu_iccm_rd_ecc_single_err, iccm_repair_state_ns, e4_valid, internal_dbg_halt_mode, lsu_pmu_load_external_m, lsu_pmu_store_external_m, tlu_flush_lower_r, tlu_i0_kill_writeb_r, internal_dbg_halt_mode_f, force_halt}), .dout({ifu_ic_error_start_f, ifu_iccm_rd_ecc_single_err_f, iccm_repair_state_d1, e5_valid, internal_dbg_halt_mode_f, lsu_pmu_load_external_r, lsu_pmu_store_external_r, tlu_flush_lower_r_d1, dec_tlu_i0_kill_writeb_wb, internal_dbg_halt_mode_f2, dec_tlu_force_halt})); assign dec_tlu_i0_kill_writeb_r = tlu_i0_kill_writeb_r; assign nmi_int_detected = (nmi_int_sync & ~nmi_int_delayed) | nmi_lsu_detected | (nmi_int_detected_f & ~take_nmi_r_d1) | nmi_fir_type; // if the first nmi is a lsu type, note it. If there's already an nmi pending, ignore. Simultaneous with FIR, drop. assign nmi_lsu_load_type = (nmi_lsu_detected & lsu_imprecise_error_load_any & ~(nmi_int_detected_f & ~take_nmi_r_d1)) | (nmi_lsu_load_type_f & ~take_nmi_r_d1); assign nmi_lsu_store_type = (nmi_lsu_detected & lsu_imprecise_error_store_any & ~(nmi_int_detected_f & ~take_nmi_r_d1)) | (nmi_lsu_store_type_f & ~take_nmi_r_d1); assign nmi_fir_type = ~nmi_int_detected_f & take_ext_int_start_d3 & |lsu_fir_error[1:0]; // Filter subsequent bus errors after the first, until the lock on MDSEAC is cleared assign nmi_lsu_detected = ~mdseac_locked_f & (lsu_imprecise_error_load_any | lsu_imprecise_error_store_any) & ~nmi_fir_type; localparam MSTATUS_MIE = 0; localparam int MSTATUS_MPIE = 1; `ifdef RV_USER_MODE localparam MSTATUS_MPP = 2; localparam MSTATUS_MPRV = 3; `endif localparam MIP_MCEIP = 5; localparam MIP_MITIP0 = 4; localparam MIP_MITIP1 = 3; localparam MIP_MEIP = 2; localparam MIP_MTIP = 1; localparam MIP_MSIP = 0; localparam MIE_MCEIE = 5; localparam MIE_MITIE0 = 4; localparam MIE_MITIE1 = 3; localparam MIE_MEIE = 2; localparam MIE_MTIE = 1; localparam MIE_MSIE = 0; localparam DCSR_EBREAKM = 15; localparam DCSR_STEPIE = 11; localparam DCSR_STOPC = 10; localparam DCSR_STEP = 2; `ifdef RV_USER_MODE localparam MCOUNTEREN_CY = 0; localparam MCOUNTEREN_IR = 1; localparam MCOUNTEREN_HPM3 = 2; localparam MCOUNTEREN_HPM4 = 3; localparam MCOUNTEREN_HPM5 = 4; localparam MCOUNTEREN_HPM6 = 5; localparam MSECCFG_RLB = 2; localparam MSECCFG_MMWP = 1; localparam MSECCFG_MML = 0; `endif // ---------------------------------------------------------------------- // MISA (RO) // [31:30] XLEN - implementation width, 2'b01 - 32 bits // [20] U - user mode support (if enabled in config) // [12] M - integer mul/div // [8] I - RV32I // [2] C - Compressed extension localparam MISA = 12'h301; // MVENDORID, MARCHID, MIMPID, MHARTID localparam MVENDORID = 12'hf11; localparam MARCHID = 12'hf12; localparam MIMPID = 12'hf13; localparam MHARTID = 12'hf14; // ---------------------------------------------------------------------- // MSTATUS (RW) // [17] MPRV : Modify PRiVilege (if enabled in config) // [12:11] MPP : Prior priv level, either 2'b11 (machine) or 2'b00 (user) // [7] MPIE : Int enable previous [1] // [3] MIE : Int enable [0] localparam MSTATUS = 12'h300; // ---------------------------------------------------------------------- // MTVEC (RW) // [31:2] BASE : Trap vector base address // [1] - Reserved, not implemented, reads zero // [0] MODE : 0 = Direct, 1 = Asyncs are vectored to BASE + (4 * CAUSE) localparam MTVEC = 12'h305; // ---------------------------------------------------------------------- // MIP (RW) // // [30] MCEIP : (RO) M-Mode Correctable Error interrupt pending // [29] MITIP0 : (RO) M-Mode Internal Timer0 interrupt pending // [28] MITIP1 : (RO) M-Mode Internal Timer1 interrupt pending // [11] MEIP : (RO) M-Mode external interrupt pending // [7] MTIP : (RO) M-Mode timer interrupt pending // [3] MSIP : (RO) M-Mode software interrupt pending localparam MIP = 12'h344; // ---------------------------------------------------------------------- // MIE (RW) // [30] MCEIE : (RO) M-Mode Correctable Error interrupt enable // [29] MITIE0 : (RO) M-Mode Internal Timer0 interrupt enable // [28] MITIE1 : (RO) M-Mode Internal Timer1 interrupt enable // [11] MEIE : (RW) M-Mode external interrupt enable // [7] MTIE : (RW) M-Mode timer interrupt enable // [3] MSIE : (RW) M-Mode software interrupt enable localparam MIE = 12'h304; // ---------------------------------------------------------------------- // MCYCLEL (RW) // [31:0] : Lower Cycle count localparam MCYCLEL = 12'hb00; localparam logic [11:0] CYCLEL = 12'hc00; // ---------------------------------------------------------------------- // MCYCLEH (RW) // [63:32] : Higher Cycle count // Chained with mcyclel. Note: mcyclel overflow due to a mcycleh write gets ignored. localparam MCYCLEH = 12'hb80; localparam logic [11:0] CYCLEH = 12'hc80; // ---------------------------------------------------------------------- // MINSTRETL (RW) // [31:0] : Lower Instruction retired count // From the spec "Some CSRs, such as the instructions retired counter, instret, may be modified as side effects // of instruction execution. In these cases, if a CSR access instruction reads a CSR, it reads the // value prior to the execution of the instruction. If a CSR access instruction writes a CSR, the // update occurs after the execution of the instruction. In particular, a value written to instret by // one instruction will be the value read by the following instruction (i.e., the increment of instret // caused by the first instruction retiring happens before the write of the new value)." localparam MINSTRETL = 12'hb02; localparam logic [11:0] INSTRETL = 12'hc02; // ---------------------------------------------------------------------- // MINSTRETH (RW) // [63:32] : Higher Instret count // Chained with minstretl. Note: minstretl overflow due to a minstreth write gets ignored. localparam MINSTRETH = 12'hb82; localparam logic [11:0] INSTRETH = 12'hc82; // ---------------------------------------------------------------------- // MSCRATCH (RW) // [31:0] : Scratch register localparam MSCRATCH = 12'h340; // ---------------------------------------------------------------------- // MEPC (RW) // [31:1] : Exception PC localparam MEPC = 12'h341; // ---------------------------------------------------------------------- // MCAUSE (RW) // [31:0] : Exception Cause localparam MCAUSE = 12'h342; // ---------------------------------------------------------------------- // MSCAUSE (RW) // [2:0] : Secondary exception Cause localparam MSCAUSE = 12'h7ff; // ---------------------------------------------------------------------- // MTVAL (RW) // [31:0] : Exception address if relevant localparam MTVAL = 12'h343; // ---------------------------------------------------------------------- // MCGC (RW) Clock gating control // [31:10]: Reserved, reads 0x0 // [9] : picio_clk_override // [7] : dec_clk_override // [6] : Unused // [5] : ifu_clk_override // [4] : lsu_clk_override // [3] : bus_clk_override // [2] : pic_clk_override // [1] : dccm_clk_override // [0] : icm_clk_override // localparam MCGC = 12'h7f8; // ---------------------------------------------------------------------- // MFDC (RW) Feature Disable Control // [31:19] : Reserved, reads 0x0 // [18:16] : DMA QoS Prty // [15:13] : Reserved, reads 0x0 // [12] : Disable trace // [11] : Disable external load forwarding // [10] : Disable dual issue // [9] : Disable pic multiple ints // [8] : Disable core ecc // [7] : Disable secondary alu?s // [6] : Unused, 0x0 // [5] : Disable non-blocking loads/divides // [4] : Disable fast divide // [3] : Disable branch prediction and return stack // [2] : Disable write buffer coalescing // [1] : Disable load misses that bypass the write buffer // [0] : Disable pipelining - Enable single instruction execution // localparam MFDC = 12'h7f9; // ---------------------------------------------------------------------- // MRAC (RW) // [31:0] : Region Access Control Register, 16 regions, {side_effect, cachable} pairs localparam MRAC = 12'h7c0; // ---------------------------------------------------------------------- // MDEAU (WAR0) // [31:0] : Dbus Error Address Unlock register // localparam MDEAU = 12'hbc0; // ---------------------------------------------------------------------- // MDSEAC (R) // [31:0] : Dbus Store Error Address Capture register // localparam MDSEAC = 12'hfc0; // ---------------------------------------------------------------------- // MPMC (R0W1) // [0] : FW halt // [1] : Set MSTATUS[MIE] on halt localparam MPMC = 12'h7c6; // ---------------------------------------------------------------------- // MICECT (I-Cache error counter/threshold) // [31:27] : Icache parity error threshold // [26:0] : Icache parity error count localparam MICECT = 12'h7f0; // ---------------------------------------------------------------------- // MICCMECT (ICCM error counter/threshold) // [31:27] : ICCM parity error threshold // [26:0] : ICCM parity error count localparam MICCMECT = 12'h7f1; // ---------------------------------------------------------------------- // MDCCMECT (DCCM error counter/threshold) // [31:27] : DCCM parity error threshold // [26:0] : DCCM parity error count localparam MDCCMECT = 12'h7f2; // ---------------------------------------------------------------------- // MFDHT (Force Debug Halt Threshold) // [5:1] : Halt timeout threshold (power of 2) // [0] : Halt timeout enabled localparam MFDHT = 12'h7ce; // ---------------------------------------------------------------------- // MFDHS(RW) // [1] : LSU operation pending when debug halt threshold reached // [0] : IFU operation pending when debug halt threshold reached localparam MFDHS = 12'h7cf; // ---------------------------------------------------------------------- // MEIVT (External Interrupt Vector Table (R/W)) // [31:10]: Base address (R/W) // [9:0] : Reserved, reads 0x0 localparam MEIVT = 12'hbc8; // ---------------------------------------------------------------------- // MEICURPL (R/W) // [31:4] : Reserved (read 0x0) // [3:0] : CURRPRI - Priority level of current interrupt service routine (R/W) localparam MEICURPL = 12'hbcc; // ---------------------------------------------------------------------- // MEICIDPL (R/W) // [31:4] : Reserved (read 0x0) // [3:0] : External Interrupt Claim ID's Priority Level Register localparam MEICIDPL = 12'hbcb; // ---------------------------------------------------------------------- // MEICPCT (Capture CLAIMID in MEIHAP and PL in MEICIDPL // [31:1] : Reserved (read 0x0) // [0] : Capture (W1, Read 0) localparam MEICPCT = 12'hbca; // ---------------------------------------------------------------------- // MEIPT (External Interrupt Priority Threshold) // [31:4] : Reserved (read 0x0) // [3:0] : PRITHRESH localparam MEIPT = 12'hbc9; // ---------------------------------------------------------------------- // DCSR (R/W) (Only accessible in debug mode) // [31:28] : xdebugver (hard coded to 0x4) RO // [27:16] : 0x0, reserved // [15] : ebreakm // [14] : 0x0, reserved // [13] : ebreaks (0x0 for this core) // [12] : ebreaku (0x0 for this core) // [11] : stepie // [10] : stopcount // [9] : 0x0 //stoptime // [8:6] : cause (RO) // [5:4] : 0x0, reserved // [3] : nmip // [2] : step // [1:0] : prv (0x3 for this core) // localparam DCSR = 12'h7b0; // ---------------------------------------------------------------------- // DPC (R/W) (Only accessible in debug mode) // [31:0] : Debug PC localparam DPC = 12'h7b1; // ---------------------------------------------------------------------- // DICAWICS (R/W) (Only accessible in debug mode) // [31:25] : Reserved // [24] : Array select, 0 is data, 1 is tag // [23:22] : Reserved // [21:20] : Way select // [19:17] : Reserved // [16:3] : Index // [2:0] : Reserved localparam DICAWICS = 12'h7c8; // ---------------------------------------------------------------------- // DICAD0 (R/W) (Only accessible in debug mode) // // If dicawics[array] is 0 // [31:0] : inst data // // If dicawics[array] is 1 // [31:16] : Tag // [15:7] : Reserved // [6:4] : LRU // [3:1] : Reserved // [0] : Valid localparam DICAD0 = 12'h7c9; // ---------------------------------------------------------------------- // DICAD0H (R/W) (Only accessible in debug mode) // // If dicawics[array] is 0 // [63:32] : inst data // localparam DICAD0H = 12'h7cc; // ---------------------------------------------------------------------- // DICAGO (R/W) (Only accessible in debug mode) // [0] : Go localparam DICAGO = 12'h7cb; // ---------------------------------------------------------------------- // MHPMC3H(RW), MHPMC3(RW) // [63:32][31:0] : Hardware Performance Monitor Counter 3 localparam MHPMC3 = 12'hB03; localparam MHPMC3H = 12'hB83; `ifdef RV_USER_MODE localparam HPMC3 = 12'hC03; localparam HPMC3H = 12'hC83; `endif // ---------------------------------------------------------------------- // MHPMC4H(RW), MHPMC4(RW) // [63:32][31:0] : Hardware Performance Monitor Counter 4 localparam MHPMC4 = 12'hB04; localparam MHPMC4H = 12'hB84; `ifdef RV_USER_MODE localparam HPMC4 = 12'hC04; localparam HPMC4H = 12'hC84; `endif // ---------------------------------------------------------------------- // MHPMC5H(RW), MHPMC5(RW) // [63:32][31:0] : Hardware Performance Monitor Counter 5 localparam MHPMC5 = 12'hB05; localparam MHPMC5H = 12'hB85; `ifdef RV_USER_MODE localparam HPMC5 = 12'hC05; localparam HPMC5H = 12'hC85; `endif // ---------------------------------------------------------------------- // MHPMC6H(RW), MHPMC6(RW) // [63:32][31:0] : Hardware Performance Monitor Counter 6 localparam MHPMC6 = 12'hB06; localparam MHPMC6H = 12'hB86; `ifdef RV_USER_MODE localparam HPMC6 = 12'hC06; localparam HPMC6H = 12'hC86; `endif // ---------------------------------------------------------------------- // MHPME3(RW) // [9:0] : Hardware Performance Monitor Event 3 localparam MHPME3 = 12'h323; // ---------------------------------------------------------------------- // MHPME4(RW) // [9:0] : Hardware Performance Monitor Event 4 localparam MHPME4 = 12'h324; // ---------------------------------------------------------------------- // MHPME5(RW) // [9:0] : Hardware Performance Monitor Event 5 localparam MHPME5 = 12'h325; // ---------------------------------------------------------------------- // MHPME6(RW) // [9:0] : Hardware Performance Monitor Event 6 localparam MHPME6 = 12'h326; // MCOUNTINHIBIT(RW) // [31:7] : Reserved, read 0x0 // [6] : HPM6 disable // [5] : HPM5 disable // [4] : HPM4 disable // [3] : HPM3 disable // [2] : MINSTRET disable // [1] : reserved, read 0x0 // [0] : MCYCLE disable localparam MCOUNTINHIBIT = 12'h320; // ---------------------------------------------------------------------- // MTSEL (R/W) // [1:0] : Trigger select : 00, 01, 10 are data/address triggers. 11 is inst count localparam MTSEL = 12'h7a0; // ---------------------------------------------------------------------- // MTDATA1 (R/W) // [31:0] : Trigger Data 1 localparam MTDATA1 = 12'h7a1; // ---------------------------------------------------------------------- // MTDATA2 (R/W) // [31:0] : Trigger Data 2 localparam MTDATA2 = 12'h7a2; assign reset_delayed = reset_detect ^ reset_detected; // ---------------------------------------------------------------------- // MPC halt // - can interact with debugger halt and v-v // fast ints in progress have priority assign mpc_debug_halt_req_sync = mpc_debug_halt_req_sync_raw & ~ext_int_freeze_d1; rvdffie #(16) mpvhalt_ff (.*, .clk(free_l2clk), .din({1'b1, reset_detect, nmi_int_sync, nmi_int_detected, nmi_lsu_load_type, nmi_lsu_store_type, mpc_debug_halt_req_sync, mpc_debug_run_req_sync, mpc_halt_state_ns, mpc_run_state_ns, debug_brkpt_status_ns, mpc_debug_halt_ack_ns, mpc_debug_run_ack_ns, dbg_halt_state_ns, dbg_run_state_ns, dec_tlu_mpc_halted_only_ns}), .dout({reset_detect, reset_detected, nmi_int_delayed, nmi_int_detected_f, nmi_lsu_load_type_f, nmi_lsu_store_type_f, mpc_debug_halt_req_sync_f, mpc_debug_run_req_sync_f, mpc_halt_state_f, mpc_run_state_f, debug_brkpt_status_f, mpc_debug_halt_ack_f, mpc_debug_run_ack_f, dbg_halt_state_f, dbg_run_state_f, dec_tlu_mpc_halted_only})); // turn level sensitive requests into pulses assign mpc_debug_halt_req_sync_pulse = mpc_debug_halt_req_sync & ~mpc_debug_halt_req_sync_f; assign mpc_debug_run_req_sync_pulse = mpc_debug_run_req_sync & ~mpc_debug_run_req_sync_f; // states assign mpc_halt_state_ns = (mpc_halt_state_f | mpc_debug_halt_req_sync_pulse | (reset_delayed & ~mpc_reset_run_req)) & ~mpc_debug_run_req_sync; assign mpc_run_state_ns = (mpc_run_state_f | (mpc_debug_run_req_sync_pulse & ~mpc_debug_run_ack_f)) & (internal_dbg_halt_mode_f & ~dcsr_single_step_running_f); // note, MPC halt can allow the jtag debugger to just start sending commands. When that happens, set the interal debugger halt state to prevent // MPC run from starting the core. assign dbg_halt_state_ns = (dbg_halt_state_f | (dbg_halt_req_final | dcsr_single_step_done_f | trigger_hit_dmode_r_d1 | ebreak_to_debug_mode_r_d1)) & ~dbg_resume_req; assign dbg_run_state_ns = (dbg_run_state_f | dbg_resume_req) & (internal_dbg_halt_mode_f & ~dcsr_single_step_running_f); // tell dbg we are only MPC halted assign dec_tlu_mpc_halted_only_ns = ~dbg_halt_state_f & mpc_halt_state_f; // this asserts from detection of bkpt until after we leave debug mode assign debug_brkpt_valid = ebreak_to_debug_mode_r_d1 | trigger_hit_dmode_r_d1; assign debug_brkpt_status_ns = (debug_brkpt_valid | debug_brkpt_status_f) & (internal_dbg_halt_mode & ~dcsr_single_step_running_f); // acks back to interface assign mpc_debug_halt_ack_ns = (mpc_halt_state_f & internal_dbg_halt_mode_f & mpc_debug_halt_req_sync & core_empty) | (mpc_debug_halt_ack_f & mpc_debug_halt_req_sync); assign mpc_debug_run_ack_ns = (mpc_debug_run_req_sync & ~internal_dbg_halt_mode & ~mpc_debug_halt_req_sync) | (mpc_debug_run_ack_f & mpc_debug_run_req_sync) ; // Pins assign mpc_debug_halt_ack = mpc_debug_halt_ack_f; assign mpc_debug_run_ack = mpc_debug_run_ack_f; assign debug_brkpt_status = debug_brkpt_status_f; // DBG halt req is a pulse, fast ext int in progress has priority assign dbg_halt_req_held_ns = (dbg_halt_req | dbg_halt_req_held) & ext_int_freeze_d1; assign dbg_halt_req_final = (dbg_halt_req | dbg_halt_req_held) & ~ext_int_freeze_d1; // combine MPC and DBG halt requests assign debug_halt_req = (dbg_halt_req_final | mpc_debug_halt_req_sync | (reset_delayed & ~mpc_reset_run_req)) & ~internal_dbg_halt_mode_f & ~ext_int_freeze_d1; assign debug_resume_req = ~debug_resume_req_f & // squash back to back resumes ((mpc_run_state_ns & ~dbg_halt_state_ns) | // MPC run req (dbg_run_state_ns & ~mpc_halt_state_ns)); // dbg request is a pulse // HALT // dbg/pmu/fw requests halt, service as soon as lsu is not blocking interrupts assign take_halt = (debug_halt_req_f | pmu_fw_halt_req_f) & ~synchronous_flush_r & ~mret_r & ~halt_taken_f & ~dec_tlu_flush_noredir_r_d1 & ~take_reset; // hold after we take a halt, so we don't keep taking halts assign halt_taken = (dec_tlu_flush_noredir_r_d1 & ~dec_tlu_flush_pause_r_d1 & ~take_ext_int_start_d1) | (halt_taken_f & ~dbg_tlu_halted_f & ~pmu_fw_tlu_halted_f & ~interrupt_valid_r_d1); // After doing halt flush (RFNPC) wait until core is idle before asserting a particular halt mode // It takes a cycle for mb_empty to assert after a fetch, take_halt covers that cycle assign core_empty = force_halt | (lsu_idle_any & lsu_idle_any_f & ifu_miss_state_idle & ifu_miss_state_idle_f & ~debug_halt_req & ~debug_halt_req_d1 & ~dec_div_active); assign dec_tlu_core_empty = core_empty; //-------------------------------------------------------------------------------- // Debug start // assign enter_debug_halt_req = (~internal_dbg_halt_mode_f & debug_halt_req) | dcsr_single_step_done_f | trigger_hit_dmode_r_d1 | ebreak_to_debug_mode_r_d1; // dbg halt state active from request until non-step resume assign internal_dbg_halt_mode = debug_halt_req_ns | (internal_dbg_halt_mode_f & ~(debug_resume_req_f & ~dcsr[DCSR_STEP])); // dbg halt can access csrs as long as we are not stepping assign allow_dbg_halt_csr_write = internal_dbg_halt_mode_f & ~dcsr_single_step_running_f; // hold debug_halt_req_ns high until we enter debug halt assign debug_halt_req_ns = enter_debug_halt_req | (debug_halt_req_f & ~dbg_tlu_halted); assign dbg_tlu_halted = (debug_halt_req_f & core_empty & halt_taken) | (dbg_tlu_halted_f & ~debug_resume_req_f); assign resume_ack_ns = (debug_resume_req_f & dbg_tlu_halted_f & dbg_run_state_ns); assign dcsr_single_step_done = dec_tlu_i0_valid_r & ~dec_tlu_dbg_halted & dcsr[DCSR_STEP] & ~rfpc_i0_r; assign dcsr_single_step_running = (debug_resume_req_f & dcsr[DCSR_STEP]) | (dcsr_single_step_running_f & ~dcsr_single_step_done_f); assign dbg_cmd_done_ns = dec_tlu_i0_valid_r & dec_tlu_dbg_halted; // used to hold off commits after an in-pipe debug mode request (triggers, DCSR) assign request_debug_mode_r = (trigger_hit_dmode_r | ebreak_to_debug_mode_r) | (request_debug_mode_r_d1 & ~dec_tlu_flush_lower_wb); assign request_debug_mode_done = (request_debug_mode_r_d1 | request_debug_mode_done_f) & ~dbg_tlu_halted_f; rvdffie #(18) halt_ff (.*, .clk(free_l2clk), .din({dec_tlu_flush_noredir_r, halt_taken, lsu_idle_any, ifu_miss_state_idle, dbg_tlu_halted, resume_ack_ns, debug_halt_req_ns, debug_resume_req, trigger_hit_dmode_r, dcsr_single_step_done, debug_halt_req, dec_tlu_wr_pause_r, dec_pause_state, request_debug_mode_r, request_debug_mode_done, dcsr_single_step_running, dec_tlu_flush_pause_r, dbg_halt_req_held_ns}), .dout({dec_tlu_flush_noredir_r_d1, halt_taken_f, lsu_idle_any_f, ifu_miss_state_idle_f, dbg_tlu_halted_f, dec_tlu_resume_ack , debug_halt_req_f, debug_resume_req_f_raw, trigger_hit_dmode_r_d1, dcsr_single_step_done_f, debug_halt_req_d1, dec_tlu_wr_pause_r_d1, dec_pause_state_f, request_debug_mode_r_d1, request_debug_mode_done_f, dcsr_single_step_running_f, dec_tlu_flush_pause_r_d1, dbg_halt_req_held})); // MPC run collides with DBG halt, fix it here assign debug_resume_req_f = debug_resume_req_f_raw & ~dbg_halt_req; assign dec_tlu_debug_stall = debug_halt_req_f; assign dec_tlu_dbg_halted = dbg_tlu_halted_f; assign dec_tlu_debug_mode = internal_dbg_halt_mode_f; assign dec_tlu_pmu_fw_halted = pmu_fw_tlu_halted_f; // kill fetch redirection on flush if going to halt, or if there's a fence during db-halt assign dec_tlu_flush_noredir_r = take_halt | (fence_i_r & internal_dbg_halt_mode) | dec_tlu_flush_pause_r | (i0_trigger_hit_r & trigger_hit_dmode_r) | take_ext_int_start; assign dec_tlu_flush_extint = take_ext_int_start; // 1 cycle after writing the PAUSE counter, flush with noredir to idle F1-D. assign dec_tlu_flush_pause_r = dec_tlu_wr_pause_r_d1 & ~interrupt_valid_r & ~take_ext_int_start; // detect end of pause counter and rfpc assign pause_expired_r = ~dec_pause_state & dec_pause_state_f & ~(ext_int_ready | ce_int_ready | timer_int_ready | soft_int_ready | int_timer0_int_hold_f | int_timer1_int_hold_f | nmi_int_detected | ext_int_freeze_d1) & ~interrupt_valid_r_d1 & ~debug_halt_req_f & ~pmu_fw_halt_req_f & ~halt_taken_f; assign dec_tlu_flush_leak_one_r = dec_tlu_flush_lower_r & dcsr[DCSR_STEP] & (dec_tlu_resume_ack | dcsr_single_step_running) & ~dec_tlu_flush_noredir_r; assign dec_tlu_flush_err_r = dec_tlu_flush_lower_r & (ic_perr_r | iccm_sbecc_r); // If DM attempts to access an illegal CSR, send cmd_fail back assign dec_dbg_cmd_done = dbg_cmd_done_ns; assign dec_dbg_cmd_fail = illegal_r & dec_dbg_cmd_done; //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- // Triggers // localparam MTDATA1_DMODE = 9; localparam MTDATA1_SEL = 7; localparam MTDATA1_ACTION = 6; localparam MTDATA1_CHAIN = 5; localparam MTDATA1_MATCH = 4; localparam MTDATA1_M_ENABLED = 3; localparam MTDATA1_EXE = 2; localparam MTDATA1_ST = 1; localparam MTDATA1_LD = 0; // Prioritize trigger hits with other exceptions. // // Trigger should have highest priority except: // - trigger is an execute-data and there is an inst_access exception (lsu triggers won't fire, inst. is nop'd by decode) // - trigger is a store-data and there is a lsu_acc_exc or lsu_ma_exc. assign trigger_execute[3:0] = {mtdata1_t3[MTDATA1_EXE], mtdata1_t2[MTDATA1_EXE], mtdata1_t1[MTDATA1_EXE], mtdata1_t0[MTDATA1_EXE]}; assign trigger_data[3:0] = {mtdata1_t3[MTDATA1_SEL], mtdata1_t2[MTDATA1_SEL], mtdata1_t1[MTDATA1_SEL], mtdata1_t0[MTDATA1_SEL]}; assign trigger_store[3:0] = {mtdata1_t3[MTDATA1_ST], mtdata1_t2[MTDATA1_ST], mtdata1_t1[MTDATA1_ST], mtdata1_t0[MTDATA1_ST]}; // MSTATUS[MIE] needs to be on to take triggers unless the action is trigger to debug mode. assign trigger_enabled[3:0] = {(mtdata1_t3[MTDATA1_ACTION] | mstatus[MSTATUS_MIE]) & mtdata1_t3[MTDATA1_M_ENABLED], (mtdata1_t2[MTDATA1_ACTION] | mstatus[MSTATUS_MIE]) & mtdata1_t2[MTDATA1_M_ENABLED], (mtdata1_t1[MTDATA1_ACTION] | mstatus[MSTATUS_MIE]) & mtdata1_t1[MTDATA1_M_ENABLED], (mtdata1_t0[MTDATA1_ACTION] | mstatus[MSTATUS_MIE]) & mtdata1_t0[MTDATA1_M_ENABLED]}; // iside exceptions are always in i0 assign i0_iside_trigger_has_pri_r[3:0] = ~( (trigger_execute[3:0] & trigger_data[3:0] & {4{inst_acc_r_raw}}) | // exe-data with inst_acc ({4{exu_i0_br_error_r | exu_i0_br_start_error_r}})); // branch error in i0 // lsu excs have to line up with their respective triggers since the lsu op can be i0 assign i0_lsu_trigger_has_pri_r[3:0] = ~(trigger_store[3:0] & trigger_data[3:0] & {4{lsu_i0_exc_r_raw}}); // trigger hits have to be eval'd to cancel side effect lsu ops even though the pipe is already frozen assign i0_trigger_eval_r = dec_tlu_i0_valid_r; assign i0trigger_qual_r[3:0] = {4{i0_trigger_eval_r}} & dec_tlu_packet_r.i0trigger[3:0] & i0_iside_trigger_has_pri_r[3:0] & i0_lsu_trigger_has_pri_r[3:0] & trigger_enabled[3:0]; // Qual trigger hits assign i0_trigger_r[3:0] = ~{4{dec_tlu_flush_lower_wb | dec_tlu_dbg_halted}} & i0trigger_qual_r[3:0]; // chaining can mask raw trigger info assign i0_trigger_chain_masked_r[3:0] = {i0_trigger_r[3] & (~mtdata1_t2[MTDATA1_CHAIN] | i0_trigger_r[2]), i0_trigger_r[2] & (~mtdata1_t2[MTDATA1_CHAIN] | i0_trigger_r[3]), i0_trigger_r[1] & (~mtdata1_t0[MTDATA1_CHAIN] | i0_trigger_r[0]), i0_trigger_r[0] & (~mtdata1_t0[MTDATA1_CHAIN] | i0_trigger_r[1])}; // This is the highest priority by this point. assign i0_trigger_hit_raw_r = |i0_trigger_chain_masked_r[3:0]; assign i0_trigger_hit_r = i0_trigger_hit_raw_r; // Actions include breakpoint, or dmode. Dmode is only possible if the DMODE bit is set. // Otherwise, take a breakpoint. assign trigger_action[3:0] = {mtdata1_t3[MTDATA1_ACTION] & mtdata1_t3[MTDATA1_DMODE], mtdata1_t2[MTDATA1_ACTION] & mtdata1_t2[MTDATA1_DMODE] & ~mtdata1_t2[MTDATA1_CHAIN], mtdata1_t1[MTDATA1_ACTION] & mtdata1_t1[MTDATA1_DMODE], mtdata1_t0[MTDATA1_ACTION] & mtdata1_t0[MTDATA1_DMODE] & ~mtdata1_t0[MTDATA1_CHAIN]}; // this is needed to set the HIT bit in the triggers assign update_hit_bit_r[3:0] = ({4{|i0_trigger_r[3:0] & ~rfpc_i0_r}} & {i0_trigger_chain_masked_r[3], i0_trigger_r[2], i0_trigger_chain_masked_r[1], i0_trigger_r[0]}); // action, 1 means dmode. Simultaneous triggers with at least 1 set for dmode force entire action to dmode. assign i0_trigger_action_r = |(i0_trigger_chain_masked_r[3:0] & trigger_action[3:0]); assign trigger_hit_dmode_r = (i0_trigger_hit_r & i0_trigger_action_r); assign mepc_trigger_hit_sel_pc_r = i0_trigger_hit_r & ~trigger_hit_dmode_r; // // Debug end //-------------------------------------------------------------------------------- //---------------------------------------------------------------------- // // Commit // //---------------------------------------------------------------------- //-------------------------------------------------------------------------------- // External halt (not debug halt) // - Fully interlocked handshake // i_cpu_halt_req ____|--------------|_______________ // core_empty ---------------|___________ // o_cpu_halt_ack _________________|----|__________ // o_cpu_halt_status _______________|---------------------|_________ // i_cpu_run_req ______|----------|____ // o_cpu_run_ack ____________|------|________ // // debug mode has priority, ignore PMU/FW halt/run while in debug mode assign i_cpu_halt_req_sync_qual = i_cpu_halt_req_sync & ~dec_tlu_debug_mode & ~ext_int_freeze_d1; assign i_cpu_run_req_sync_qual = i_cpu_run_req_sync & ~dec_tlu_debug_mode & pmu_fw_tlu_halted_f & ~ext_int_freeze_d1; rvdffie #(10) exthaltff (.*, .clk(free_l2clk), .din({i_cpu_halt_req_sync_qual, i_cpu_run_req_sync_qual, cpu_halt_status, cpu_halt_ack, cpu_run_ack, internal_pmu_fw_halt_mode, pmu_fw_halt_req_ns, pmu_fw_tlu_halted, int_timer0_int_hold, int_timer1_int_hold}), .dout({i_cpu_halt_req_d1, i_cpu_run_req_d1_raw, o_cpu_halt_status, o_cpu_halt_ack, o_cpu_run_ack, internal_pmu_fw_halt_mode_f, pmu_fw_halt_req_f, pmu_fw_tlu_halted_f, int_timer0_int_hold_f, int_timer1_int_hold_f})); // only happens if we aren't in dgb_halt assign ext_halt_pulse = i_cpu_halt_req_sync_qual & ~i_cpu_halt_req_d1; assign enter_pmu_fw_halt_req = ext_halt_pulse | fw_halt_req; assign pmu_fw_halt_req_ns = (enter_pmu_fw_halt_req | (pmu_fw_halt_req_f & ~pmu_fw_tlu_halted)) & ~debug_halt_req_f; assign internal_pmu_fw_halt_mode = pmu_fw_halt_req_ns | (internal_pmu_fw_halt_mode_f & ~i_cpu_run_req_d1 & ~debug_halt_req_f); // debug halt has priority assign pmu_fw_tlu_halted = ((pmu_fw_halt_req_f & core_empty & halt_taken & ~enter_debug_halt_req) | (pmu_fw_tlu_halted_f & ~i_cpu_run_req_d1)) & ~debug_halt_req_f; assign cpu_halt_ack = (i_cpu_halt_req_d1 & pmu_fw_tlu_halted_f) | (o_cpu_halt_ack & i_cpu_halt_req_sync); assign cpu_halt_status = (pmu_fw_tlu_halted_f & ~i_cpu_run_req_d1) | (o_cpu_halt_status & ~i_cpu_run_req_d1 & ~internal_dbg_halt_mode_f); assign cpu_run_ack = (~pmu_fw_tlu_halted_f & i_cpu_run_req_sync) | (o_cpu_halt_status & i_cpu_run_req_d1_raw) | (o_cpu_run_ack & i_cpu_run_req_sync); assign debug_mode_status = internal_dbg_halt_mode_f; assign o_debug_mode_status = debug_mode_status; `ifdef RV_ASSERT_ON assert_commit_while_halted: assert #0 (~(tlu_i0_commit_cmt & o_cpu_halt_status)) else $display("ERROR: Commiting while cpu_halt_status asserted!"); assert_flush_while_fastint: assert #0 (~((take_ext_int_start_d1 | take_ext_int_start_d2) & dec_tlu_flush_lower_r)) else $display("ERROR: TLU Flushing inside fast interrupt procedure!"); `endif // high priority interrupts can wakeup from external halt, so can unmasked timer interrupts assign i_cpu_run_req_d1 = i_cpu_run_req_d1_raw | ((nmi_int_detected | timer_int_ready | soft_int_ready | int_timer0_int_hold_f | int_timer1_int_hold_f | (mhwakeup & mhwakeup_ready)) & o_cpu_halt_status & ~i_cpu_halt_req_d1); //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- assign lsu_single_ecc_error_r = lsu_single_ecc_error_incr; assign lsu_error_pkt_addr_r[31:0] = lsu_error_pkt_r.addr[31:0]; assign lsu_exc_valid_r_raw = lsu_error_pkt_r.exc_valid & ~dec_tlu_flush_lower_wb; assign lsu_i0_exc_r_raw = lsu_error_pkt_r.exc_valid; assign lsu_i0_exc_r = lsu_i0_exc_r_raw & lsu_exc_valid_r_raw & ~i0_trigger_hit_r & ~rfpc_i0_r; assign lsu_exc_valid_r = lsu_i0_exc_r; assign lsu_exc_ma_r = lsu_i0_exc_r & ~lsu_error_pkt_r.exc_type; assign lsu_exc_acc_r = lsu_i0_exc_r & lsu_error_pkt_r.exc_type; assign lsu_exc_st_r = lsu_i0_exc_r & lsu_error_pkt_r.inst_type; // Single bit ECC errors on loads are RFNPC corrected, with the corrected data written to the GPR. // LSU turns the load into a store and patches the data in the DCCM assign lsu_i0_rfnpc_r = dec_tlu_i0_valid_r & ~i0_trigger_hit_r & (~lsu_error_pkt_r.inst_type & lsu_error_pkt_r.single_ecc_error); // Final commit valids `ifdef RV_USER_MODE assign tlu_i0_commit_cmt = dec_tlu_i0_valid_r & ~rfpc_i0_r & ~lsu_i0_exc_r & ~inst_acc_r & ~dec_tlu_dbg_halted & ~request_debug_mode_r_d1 & ~i0_trigger_hit_r & ~csr_acc_r; `else assign tlu_i0_commit_cmt = dec_tlu_i0_valid_r & ~rfpc_i0_r & ~lsu_i0_exc_r & ~inst_acc_r & ~dec_tlu_dbg_halted & ~request_debug_mode_r_d1 & ~i0_trigger_hit_r; `endif // unified place to manage the killing of arch state writebacks `ifdef RV_USER_MODE assign tlu_i0_kill_writeb_r = rfpc_i0_r | lsu_i0_exc_r | inst_acc_r | (illegal_r & dec_tlu_dbg_halted) | i0_trigger_hit_r | csr_acc_r; `else assign tlu_i0_kill_writeb_r = rfpc_i0_r | lsu_i0_exc_r | inst_acc_r | (illegal_r & dec_tlu_dbg_halted) | i0_trigger_hit_r; `endif assign dec_tlu_i0_commit_cmt = tlu_i0_commit_cmt; // refetch PC, microarch flush // ic errors only in pipe0 assign rfpc_i0_r = ((dec_tlu_i0_valid_r & ~tlu_flush_lower_r_d1 & (exu_i0_br_error_r | exu_i0_br_start_error_r)) | // inst commit with rfpc ((ic_perr_r | iccm_sbecc_r) & ~ext_int_freeze_d1)) & // ic/iccm without inst commit ~i0_trigger_hit_r & // unless there's a trigger. Err signal to ic/iccm will assert anyway to clear the error. ~lsu_i0_rfnpc_r; // From the indication of a iccm single bit error until the first commit or flush, maintain a repair state. In the repair state, rfnpc i0 commits. assign iccm_repair_state_ns = iccm_sbecc_r | (iccm_repair_state_d1 & ~dec_tlu_flush_lower_r); localparam MCPC = 12'h7c2; // this is a flush of last resort, meaning only assert it if there is no other flush happening. assign iccm_repair_state_rfnpc = tlu_i0_commit_cmt & iccm_repair_state_d1 & ~(ebreak_r | ecall_r | mret_r | take_reset | illegal_r | (dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MCPC))); if(pt.BTB_ENABLE==1) begin // go ahead and repair the branch error on other flushes, doesn't have to be the rfpc flush assign dec_tlu_br0_error_r = exu_i0_br_error_r & dec_tlu_i0_valid_r & ~tlu_flush_lower_r_d1; assign dec_tlu_br0_start_error_r = exu_i0_br_start_error_r & dec_tlu_i0_valid_r & ~tlu_flush_lower_r_d1; assign dec_tlu_br0_v_r = exu_i0_br_valid_r & dec_tlu_i0_valid_r & ~tlu_flush_lower_r_d1 & (~exu_i0_br_mp_r | ~exu_pmu_i0_br_ataken); assign dec_tlu_br0_r_pkt.hist[1:0] = exu_i0_br_hist_r[1:0]; assign dec_tlu_br0_r_pkt.br_error = dec_tlu_br0_error_r; assign dec_tlu_br0_r_pkt.br_start_error = dec_tlu_br0_start_error_r; assign dec_tlu_br0_r_pkt.valid = dec_tlu_br0_v_r; assign dec_tlu_br0_r_pkt.way = exu_i0_br_way_r; assign dec_tlu_br0_r_pkt.middle = exu_i0_br_middle_r; end // if (pt.BTB_ENABLE==1) else begin assign dec_tlu_br0_error_r = '0; assign dec_tlu_br0_start_error_r = '0; assign dec_tlu_br0_v_r = '0; assign dec_tlu_br0_r_pkt = '0; end // else: !if(pt.BTB_ENABLE==1) // only expect these in pipe 0 assign ebreak_r = (dec_tlu_packet_r.pmu_i0_itype == EBREAK) & dec_tlu_i0_valid_r & ~i0_trigger_hit_r & ~dcsr[DCSR_EBREAKM] & ~rfpc_i0_r; assign ecall_r = (dec_tlu_packet_r.pmu_i0_itype == ECALL) & dec_tlu_i0_valid_r & ~i0_trigger_hit_r & ~rfpc_i0_r; `ifdef RV_USER_MODE assign illegal_r = (((dec_tlu_packet_r.pmu_i0_itype == MRET) & priv_mode) | ~dec_tlu_packet_r.legal) & dec_tlu_i0_valid_r & ~i0_trigger_hit_r & ~rfpc_i0_r; assign mret_r = ( (dec_tlu_packet_r.pmu_i0_itype == MRET) & ~priv_mode ) & dec_tlu_i0_valid_r & ~i0_trigger_hit_r & ~rfpc_i0_r; `else assign illegal_r = ~dec_tlu_packet_r.legal & dec_tlu_i0_valid_r & ~i0_trigger_hit_r & ~rfpc_i0_r; assign mret_r = (dec_tlu_packet_r.pmu_i0_itype == MRET) & dec_tlu_i0_valid_r & ~i0_trigger_hit_r & ~rfpc_i0_r; `endif // fence_i includes debug only fence_i's assign fence_i_r = (dec_tlu_packet_r.fence_i & dec_tlu_i0_valid_r & ~i0_trigger_hit_r) & ~rfpc_i0_r; assign ic_perr_r = ifu_ic_error_start_f & ~ext_int_freeze_d1 & (~internal_dbg_halt_mode_f | dcsr_single_step_running) & ~internal_pmu_fw_halt_mode_f; assign iccm_sbecc_r = ifu_iccm_rd_ecc_single_err_f & ~ext_int_freeze_d1 & (~internal_dbg_halt_mode_f | dcsr_single_step_running) & ~internal_pmu_fw_halt_mode_f; assign inst_acc_r_raw = dec_tlu_packet_r.icaf & dec_tlu_i0_valid_r; assign inst_acc_r = inst_acc_r_raw & ~rfpc_i0_r & ~i0_trigger_hit_r; assign inst_acc_second_r = dec_tlu_packet_r.icaf_second; assign ebreak_to_debug_mode_r = (dec_tlu_packet_r.pmu_i0_itype == EBREAK) & dec_tlu_i0_valid_r & ~i0_trigger_hit_r & dcsr[DCSR_EBREAKM] & ~rfpc_i0_r; rvdff #(1) exctype_wb_ff (.*, .clk(e4e5_clk), .din (ebreak_to_debug_mode_r ), .dout(ebreak_to_debug_mode_r_d1)); assign dec_tlu_fence_i_r = fence_i_r; `ifdef RV_USER_MODE // CSR access // Address bits 9:8 == 2'b00 indicate unprivileged / user-level CSR assign csr_wr_usr_r = ~|dec_csr_wraddr_r[9:8]; assign csr_rd_usr_r = ~|dec_csr_rdaddr_r[9:8]; // CSR access error // cycle and instret CSR unprivileged access is controller by bits in mcounteren CSR logic csr_wr_acc_r; logic csr_rd_acc_r; assign csr_wr_acc_r = csr_wr_usr_r & ( ((dec_csr_wraddr_r[11:0] == CYCLEL) & mcounteren[MCOUNTEREN_CY]) | ((dec_csr_wraddr_r[11:0] == CYCLEH) & mcounteren[MCOUNTEREN_CY]) | ((dec_csr_wraddr_r[11:0] == INSTRETL) & mcounteren[MCOUNTEREN_IR]) | ((dec_csr_wraddr_r[11:0] == INSTRETH) & mcounteren[MCOUNTEREN_IR]) | ((dec_csr_wraddr_r[11:0] == HPMC3) & mcounteren[MCOUNTEREN_HPM3]) | ((dec_csr_wraddr_r[11:0] == HPMC3H) & mcounteren[MCOUNTEREN_HPM3]) | ((dec_csr_wraddr_r[11:0] == HPMC4) & mcounteren[MCOUNTEREN_HPM4]) | ((dec_csr_wraddr_r[11:0] == HPMC4H) & mcounteren[MCOUNTEREN_HPM4]) | ((dec_csr_wraddr_r[11:0] == HPMC5) & mcounteren[MCOUNTEREN_HPM5]) | ((dec_csr_wraddr_r[11:0] == HPMC5H) & mcounteren[MCOUNTEREN_HPM5]) | ((dec_csr_wraddr_r[11:0] == HPMC6) & mcounteren[MCOUNTEREN_HPM6]) | ((dec_csr_wraddr_r[11:0] == HPMC6H) & mcounteren[MCOUNTEREN_HPM6])); assign csr_rd_acc_r = csr_rd_usr_r & ( ((dec_csr_rdaddr_r[11:0] == CYCLEL) & mcounteren[MCOUNTEREN_CY]) | ((dec_csr_rdaddr_r[11:0] == CYCLEH) & mcounteren[MCOUNTEREN_CY]) | ((dec_csr_rdaddr_r[11:0] == INSTRETL) & mcounteren[MCOUNTEREN_IR]) | ((dec_csr_rdaddr_r[11:0] == INSTRETH) & mcounteren[MCOUNTEREN_IR]) | ((dec_csr_rdaddr_r[11:0] == HPMC3) & mcounteren[MCOUNTEREN_HPM3]) | ((dec_csr_rdaddr_r[11:0] == HPMC3H) & mcounteren[MCOUNTEREN_HPM3]) | ((dec_csr_rdaddr_r[11:0] == HPMC4) & mcounteren[MCOUNTEREN_HPM4]) | ((dec_csr_rdaddr_r[11:0] == HPMC4H) & mcounteren[MCOUNTEREN_HPM4]) | ((dec_csr_rdaddr_r[11:0] == HPMC5) & mcounteren[MCOUNTEREN_HPM5]) | ((dec_csr_rdaddr_r[11:0] == HPMC5H) & mcounteren[MCOUNTEREN_HPM5]) | ((dec_csr_rdaddr_r[11:0] == HPMC6) & mcounteren[MCOUNTEREN_HPM6]) | ((dec_csr_rdaddr_r[11:0] == HPMC6H) & mcounteren[MCOUNTEREN_HPM6])); assign csr_acc_r = priv_mode & dec_tlu_i0_valid_r & ~i0_trigger_hit_r & ~rfpc_i0_r & ( (dec_tlu_packet_r.pmu_i0_itype == CSRREAD) & ~csr_rd_acc_r | (dec_tlu_packet_r.pmu_i0_itype == CSRWRITE) & ~csr_wr_acc_r | (dec_tlu_packet_r.pmu_i0_itype == CSRRW) & ~csr_rd_acc_r & ~csr_wr_acc_r); `endif // // Exceptions // // - MEPC <- PC // - PC <- MTVEC, assert flush_lower // - MCAUSE <- cause // - MSCAUSE <- secondary cause // - MTVAL <- // - MPIE <- MIE // - MIE <- 0 // `ifdef RV_USER_MODE assign i0_exception_valid_r = (ebreak_r | ecall_r | illegal_r | inst_acc_r | csr_acc_r) & ~rfpc_i0_r & ~dec_tlu_dbg_halted; `else assign i0_exception_valid_r = (ebreak_r | ecall_r | illegal_r | inst_acc_r) & ~rfpc_i0_r & ~dec_tlu_dbg_halted; `endif // Cause: // // 0x2 : illegal // 0x3 : breakpoint // 0x8 : Environment call U-mode (if U-mode is enabled) // 0xb : Environment call M-mode assign exc_cause_r[4:0] = ( ({5{take_ext_int}} & 5'h0b) | ({5{take_timer_int}} & 5'h07) | ({5{take_soft_int}} & 5'h03) | ({5{take_int_timer0_int}} & 5'h1d) | ({5{take_int_timer1_int}} & 5'h1c) | ({5{take_ce_int}} & 5'h1e) | `ifdef RV_USER_MODE ({5{illegal_r| csr_acc_r}} & 5'h02) | ({5{ecall_r & priv_mode}} & 5'h08) | ({5{ecall_r & ~priv_mode}} & 5'h0b) | `else ({5{illegal_r}} & 5'h02) | ({5{ecall_r}} & 5'h0b) | `endif ({5{inst_acc_r}} & 5'h01) | ({5{ebreak_r | i0_trigger_hit_r}} & 5'h03) | ({5{lsu_exc_ma_r & ~lsu_exc_st_r}} & 5'h04) | ({5{lsu_exc_acc_r & ~lsu_exc_st_r}} & 5'h05) | ({5{lsu_exc_ma_r & lsu_exc_st_r}} & 5'h06) | ({5{lsu_exc_acc_r & lsu_exc_st_r}} & 5'h07) ) & ~{5{take_nmi}}; // // Interrupts // // exceptions that are committed have already happened and will cause an int at E4 to wait a cycle // or more if MSTATUS[MIE] is cleared. // // -in priority order, highest to lowest // -single cycle window where a csr write to MIE/MSTATUS is at E4 when the other conditions for externals are met. // Hold off externals for a cycle to make sure we are consistent with what was just written assign mhwakeup_ready = ~dec_csr_stall_int_ff & mstatus_mie_ns & mip[MIP_MEIP] & mie_ns[MIE_MEIE]; assign ext_int_ready = ~dec_csr_stall_int_ff & mstatus_mie_ns & mip[MIP_MEIP] & mie_ns[MIE_MEIE] & ~ignore_ext_int_due_to_lsu_stall; assign ce_int_ready = ~dec_csr_stall_int_ff & mstatus_mie_ns & mip[MIP_MCEIP] & mie_ns[MIE_MCEIE]; assign soft_int_ready = ~dec_csr_stall_int_ff & mstatus_mie_ns & mip[MIP_MSIP] & mie_ns[MIE_MSIE]; assign timer_int_ready = ~dec_csr_stall_int_ff & mstatus_mie_ns & mip[MIP_MTIP] & mie_ns[MIE_MTIE]; // MIP for internal timers pulses for 1 clock, resets the timer counter. Mip won't hold past the various stall conditions. assign int_timer0_int_possible = mstatus_mie_ns & mie_ns[MIE_MITIE0]; assign int_timer0_int_ready = mip[MIP_MITIP0] & int_timer0_int_possible; assign int_timer1_int_possible = mstatus_mie_ns & mie_ns[MIE_MITIE1]; assign int_timer1_int_ready = mip[MIP_MITIP1] & int_timer1_int_possible; // Internal timers pulse and reset. If core is PMU/FW halted, the pulse will cause an exit from halt, but won't stick around // Make it sticky, also for 1 cycle stall conditions. assign int_timer_stalled = dec_csr_stall_int_ff | synchronous_flush_r | exc_or_int_valid_r_d1 | mret_r; assign int_timer0_int_hold = (int_timer0_int_ready & (pmu_fw_tlu_halted_f | int_timer_stalled)) | (int_timer0_int_possible & int_timer0_int_hold_f & ~interrupt_valid_r & ~take_ext_int_start & ~internal_dbg_halt_mode_f); assign int_timer1_int_hold = (int_timer1_int_ready & (pmu_fw_tlu_halted_f | int_timer_stalled)) | (int_timer1_int_possible & int_timer1_int_hold_f & ~interrupt_valid_r & ~take_ext_int_start & ~internal_dbg_halt_mode_f); assign internal_dbg_halt_timers = internal_dbg_halt_mode_f & ~dcsr_single_step_running; assign block_interrupts = ( (internal_dbg_halt_mode & (~dcsr_single_step_running | dec_tlu_i0_valid_r)) | // No ints in db-halt unless we are single stepping internal_pmu_fw_halt_mode | i_cpu_halt_req_d1 |// No ints in PMU/FW halt. First we exit halt take_nmi | // NMI is top priority ebreak_to_debug_mode_r | // Heading to debug mode, hold off ints synchronous_flush_r | // exception flush this cycle exc_or_int_valid_r_d1 | // ext/int past cycle (need time for MIE to update) mret_r | // mret in progress, for cases were ISR enables ints before mret ext_int_freeze_d1 // Fast interrupt in progress (optional) ); if (pt.FAST_INTERRUPT_REDIRECT) begin assign take_ext_int_start = ext_int_ready & ~block_interrupts; assign ext_int_freeze = take_ext_int_start | take_ext_int_start_d1 | take_ext_int_start_d2 | take_ext_int_start_d3; assign take_ext_int = take_ext_int_start_d3 & ~|lsu_fir_error[1:0]; assign fast_int_meicpct = csr_meicpct & dec_csr_any_unq_d; // MEICPCT becomes illegal if fast ints are enabled assign ignore_ext_int_due_to_lsu_stall = lsu_fastint_stall_any; end else begin assign take_ext_int_start = 1'b0; assign ext_int_freeze = 1'b0; assign ext_int_freeze_d1 = 1'b0; assign take_ext_int_start_d1 = 1'b0; assign take_ext_int_start_d2 = 1'b0; assign take_ext_int_start_d3 = 1'b0; assign fast_int_meicpct = 1'b0; assign ignore_ext_int_due_to_lsu_stall = 1'b0; assign take_ext_int = ext_int_ready & ~block_interrupts; end assign take_ce_int = ce_int_ready & ~ext_int_ready & ~block_interrupts; assign take_soft_int = soft_int_ready & ~ext_int_ready & ~ce_int_ready & ~block_interrupts; assign take_timer_int = timer_int_ready & ~soft_int_ready & ~ext_int_ready & ~ce_int_ready & ~block_interrupts; assign take_int_timer0_int = (int_timer0_int_ready | int_timer0_int_hold_f) & int_timer0_int_possible & ~dec_csr_stall_int_ff & ~timer_int_ready & ~soft_int_ready & ~ext_int_ready & ~ce_int_ready & ~block_interrupts; assign take_int_timer1_int = (int_timer1_int_ready | int_timer1_int_hold_f) & int_timer1_int_possible & ~dec_csr_stall_int_ff & ~(int_timer0_int_ready | int_timer0_int_hold_f) & ~timer_int_ready & ~soft_int_ready & ~ext_int_ready & ~ce_int_ready & ~block_interrupts; assign take_reset = reset_delayed & mpc_reset_run_req; assign take_nmi = nmi_int_detected & ~internal_pmu_fw_halt_mode & (~internal_dbg_halt_mode | (dcsr_single_step_running_f & dcsr[DCSR_STEPIE] & ~dec_tlu_i0_valid_r & ~dcsr_single_step_done_f)) & ~synchronous_flush_r & ~mret_r & ~take_reset & ~ebreak_to_debug_mode_r & (~ext_int_freeze_d1 | (take_ext_int_start_d3 & |lsu_fir_error[1:0])); assign interrupt_valid_r = take_ext_int | take_timer_int | take_soft_int | take_nmi | take_ce_int | take_int_timer0_int | take_int_timer1_int; // Compute interrupt path: // If vectored async is set in mtvec, flush path for interrupts is MTVEC + (4 * CAUSE); assign vectored_path[31:1] = {mtvec[30:1], 1'b0} + {25'b0, exc_cause_r[4:0], 1'b0}; assign interrupt_path[31:1] = take_nmi ? nmi_vec[31:1] : ((mtvec[0] == 1'b1) ? vectored_path[31:1] : {mtvec[30:1], 1'b0}); assign sel_npc_r = lsu_i0_rfnpc_r | fence_i_r | iccm_repair_state_rfnpc | (i_cpu_run_req_d1 & ~interrupt_valid_r) | (rfpc_i0_r & ~dec_tlu_i0_valid_r); assign sel_npc_resume = (i_cpu_run_req_d1 & pmu_fw_tlu_halted_f) | pause_expired_r; assign sel_fir_addr = take_ext_int_start_d3 & ~|lsu_fir_error[1:0]; assign synchronous_flush_r = i0_exception_valid_r | // exception rfpc_i0_r | // rfpc lsu_exc_valid_r | // lsu exception in either pipe 0 or pipe 1 fence_i_r | // fence, a rfnpc lsu_i0_rfnpc_r | // lsu dccm sb ecc iccm_repair_state_rfnpc | // Iccm sb ecc debug_resume_req_f | // resume from debug halt, fetch the dpc sel_npc_resume | // resume from pmu/fw halt, or from pause and fetch the NPC dec_tlu_wr_pause_r_d1 | // flush at start of pause i0_trigger_hit_r; // trigger hit, ebreak or goto debug mode assign tlu_flush_lower_r = interrupt_valid_r | mret_r | synchronous_flush_r | take_halt | take_reset | take_ext_int_start; assign tlu_flush_path_r[31:1] = take_reset ? rst_vec[31:1] : ( ({31{sel_fir_addr}} & lsu_fir_addr[31:1]) | ({31{~take_nmi & sel_npc_r}} & npc_r[31:1]) | ({31{~take_nmi & rfpc_i0_r & dec_tlu_i0_valid_r & ~sel_npc_r}} & dec_tlu_i0_pc_r[31:1]) | ({31{interrupt_valid_r & ~sel_fir_addr}} & interrupt_path[31:1]) | ({31{(i0_exception_valid_r | lsu_exc_valid_r | (i0_trigger_hit_r & ~trigger_hit_dmode_r)) & ~interrupt_valid_r & ~sel_fir_addr}} & {mtvec[30:1],1'b0}) | ({31{~take_nmi & mret_r}} & mepc[31:1]) | ({31{~take_nmi & debug_resume_req_f}} & dpc[31:1]) | ({31{~take_nmi & sel_npc_resume}} & npc_r_d1[31:1]) ); rvdffpcie #(31) flush_lower_ff (.*, .en(tlu_flush_lower_r), .din({tlu_flush_path_r[31:1]}), .dout({tlu_flush_path_r_d1[31:1]})); assign dec_tlu_flush_lower_wb = tlu_flush_lower_r_d1; assign dec_tlu_flush_lower_r = tlu_flush_lower_r; assign dec_tlu_flush_path_r[31:1] = tlu_flush_path_r[31:1]; // this is used to capture mepc, etc. assign exc_or_int_valid_r = lsu_exc_valid_r | i0_exception_valid_r | interrupt_valid_r | (i0_trigger_hit_r & ~trigger_hit_dmode_r); rvdffie #(12) excinfo_wb_ff (.*, .din({interrupt_valid_r, i0_exception_valid_r, exc_or_int_valid_r, exc_cause_r[4:0], tlu_i0_commit_cmt & ~illegal_r, i0_trigger_hit_r, take_nmi, pause_expired_r }), .dout({interrupt_valid_r_d1, i0_exception_valid_r_d1, exc_or_int_valid_r_d1, exc_cause_wb[4:0], i0_valid_wb, trigger_hit_r_d1, take_nmi_r_d1, pause_expired_wb})); `ifdef RV_USER_MODE // // Privilege mode // assign priv_mode_ns = (mret_r & mstatus[MSTATUS_MPP]) | (exc_or_int_valid_r & 1'b0 ) | ((~mret_r & ~exc_or_int_valid_r) & priv_mode); rvdff #(1) priv_ff ( .clk (free_l2clk), .rst_l (rst_l), .din (priv_mode_ns), .dout (priv_mode) ); `endif //---------------------------------------------------------------------- // // CSRs // //---------------------------------------------------------------------- // ---------------------------------------------------------------------- // MSTATUS (RW) // [17] MPRV : Modify PRiVilege (if enabled in config) // [12:11] MPP : Prior priv level, either 2'b11 (machine) or 2'b00 (user) // [7] MPIE : Int enable previous [1] // [3] MIE : Int enable [0] //When executing a MRET instruction, supposing MPP holds the value 3, MIE //is set to MPIE; the privilege mode is changed to 3; MPIE is set to 1; and MPP is set to 3 `ifdef RV_USER_MODE assign dec_csr_wen_r_mod = dec_csr_wen_r & ~i0_trigger_hit_r & ~rfpc_i0_r & ~csr_acc_r; `else assign dec_csr_wen_r_mod = dec_csr_wen_r & ~i0_trigger_hit_r & ~rfpc_i0_r; `endif assign wr_mstatus_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MSTATUS); // set this even if we don't go to fwhalt due to debug halt. We committed the inst, so ... assign set_mie_pmu_fw_halt = ~mpmc_b_ns[1] & fw_halt_req; `ifdef RV_USER_MODE // mstatus[2] / mstatus_ns[2] actually stores inverse of the MPP field ! assign mstatus_ns[3:0] = ( ({4{~wr_mstatus_r & exc_or_int_valid_r}} & {mstatus[MSTATUS_MPRV], priv_mode, mstatus[MSTATUS_MIE], 1'b0}) | ({4{ wr_mstatus_r & exc_or_int_valid_r}} & {mstatus[MSTATUS_MPRV], priv_mode, dec_csr_wrdata_r[3], 1'b0}) | ({4{mret_r & ~exc_or_int_valid_r}} & {mstatus[MSTATUS_MPRV] & ~mstatus[MSTATUS_MPP], 1'b1, 1'b1, mstatus[MSTATUS_MPIE]}) | ({4{set_mie_pmu_fw_halt}} & {mstatus[3:2], mstatus[MSTATUS_MPIE], 1'b1}) | ({4{wr_mstatus_r & ~exc_or_int_valid_r}} & {dec_csr_wrdata_r[17], ~dec_csr_wrdata_r[12], dec_csr_wrdata_r[7], dec_csr_wrdata_r[3]}) | ({4{~wr_mstatus_r & ~exc_or_int_valid_r & ~mret_r & ~set_mie_pmu_fw_halt}} & mstatus[3:0]) ); // gate MIE if we are single stepping and DCSR[STEPIE] is off // in user mode machine interrupts are always enabled as per RISC-V privilege spec (chapter 3.1.6.1). assign mstatus_mie_ns = (priv_mode | mstatus[MSTATUS_MIE]) & (~dcsr_single_step_running_f | dcsr[DCSR_STEPIE]); // set effective privilege mode according to MPRV and MPP assign priv_mode_eff = ( mstatus[MSTATUS_MPRV] & mstatus[MSTATUS_MPP]) | // MPRV=1, use MPP (~mstatus[MSTATUS_MPRV] & priv_mode); // MPRV=0, use current operating mode `else assign mstatus_ns[1:0] = ( ({2{~wr_mstatus_r & exc_or_int_valid_r}} & {mstatus[MSTATUS_MIE], 1'b0}) | ({2{ wr_mstatus_r & exc_or_int_valid_r}} & {dec_csr_wrdata_r[3], 1'b0}) | ({2{mret_r & ~exc_or_int_valid_r}} & {1'b1, mstatus[MSTATUS_MPIE]}) | ({2{set_mie_pmu_fw_halt}} & {mstatus[MSTATUS_MPIE], 1'b1}) | ({2{wr_mstatus_r & ~exc_or_int_valid_r}} & {dec_csr_wrdata_r[7], dec_csr_wrdata_r[3]}) | ({2{~wr_mstatus_r & ~exc_or_int_valid_r & ~mret_r & ~set_mie_pmu_fw_halt}} & mstatus[1:0]) ); assign mstatus_mie_ns = mstatus[MSTATUS_MIE] & (~dcsr_single_step_running_f | dcsr[DCSR_STEPIE]); `endif // ---------------------------------------------------------------------- // MTVEC (RW) // [31:2] BASE : Trap vector base address // [1] - Reserved, not implemented, reads zero // [0] MODE : 0 = Direct, 1 = Asyncs are vectored to BASE + (4 * CAUSE) assign wr_mtvec_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTVEC); assign mtvec_ns[30:0] = {dec_csr_wrdata_r[31:2], dec_csr_wrdata_r[0]} ; rvdffe #(31) mtvec_ff (.*, .en(wr_mtvec_r), .din(mtvec_ns[30:0]), .dout(mtvec[30:0])); // ---------------------------------------------------------------------- // MIP (RW) // // [30] MCEIP : (RO) M-Mode Correctable Error interrupt pending // [29] MITIP0 : (RO) M-Mode Internal Timer0 interrupt pending // [28] MITIP1 : (RO) M-Mode Internal Timer1 interrupt pending // [11] MEIP : (RO) M-Mode external interrupt pending // [7] MTIP : (RO) M-Mode timer interrupt pending // [3] MSIP : (RO) M-Mode software interrupt pending assign ce_int = (mdccme_ce_req | miccme_ce_req | mice_ce_req); assign mip_ns[5:0] = {ce_int, dec_timer_t0_pulse, dec_timer_t1_pulse, mexintpend, timer_int_sync, soft_int_sync}; // ---------------------------------------------------------------------- // MIE (RW) // [30] MCEIE : (RO) M-Mode Correctable Error interrupt enable // [29] MITIE0 : (RO) M-Mode Internal Timer0 interrupt enable // [28] MITIE1 : (RO) M-Mode Internal Timer1 interrupt enable // [11] MEIE : (RW) M-Mode external interrupt enable // [7] MTIE : (RW) M-Mode timer interrupt enable // [3] MSIE : (RW) M-Mode software interrupt enable assign wr_mie_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MIE); assign mie_ns[5:0] = wr_mie_r ? {dec_csr_wrdata_r[30:28], dec_csr_wrdata_r[11], dec_csr_wrdata_r[7], dec_csr_wrdata_r[3]} : mie[5:0]; rvdff #(6) mie_ff (.*, .clk(csr_wr_clk), .din(mie_ns[5:0]), .dout(mie[5:0])); // ---------------------------------------------------------------------- // MCYCLEL (RW) // [31:0] : Lower Cycle count assign kill_ebreak_count_r = ebreak_to_debug_mode_r & dcsr[DCSR_STOPC]; assign wr_mcyclel_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MCYCLEL); assign mcyclel_cout_in = ~(kill_ebreak_count_r | (dec_tlu_dbg_halted & dcsr[DCSR_STOPC]) | dec_tlu_pmu_fw_halted | mcountinhibit[0]); // split for power assign {mcyclela_cout, mcyclel_inc[7:0]} = mcyclel[7:0] + {7'b0, 1'b1}; assign {mcyclel_cout, mcyclel_inc[31:8]} = mcyclel[31:8] + {23'b0, mcyclela_cout}; assign mcyclel_ns[31:0] = wr_mcyclel_r ? dec_csr_wrdata_r[31:0] : mcyclel_inc[31:0]; rvdffe #(24) mcyclel_bff (.*, .clk(free_l2clk), .en(wr_mcyclel_r | (mcyclela_cout & mcyclel_cout_in)), .din(mcyclel_ns[31:8]), .dout(mcyclel[31:8])); rvdffe #(8) mcyclel_aff (.*, .clk(free_l2clk), .en(wr_mcyclel_r | mcyclel_cout_in), .din(mcyclel_ns[7:0]), .dout(mcyclel[7:0])); // ---------------------------------------------------------------------- // MCYCLEH (RW) // [63:32] : Higher Cycle count // Chained with mcyclel. Note: mcyclel overflow due to a mcycleh write gets ignored. assign wr_mcycleh_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MCYCLEH); assign mcycleh_inc[31:0] = mcycleh[31:0] + {31'b0, mcyclel_cout_f}; assign mcycleh_ns[31:0] = wr_mcycleh_r ? dec_csr_wrdata_r[31:0] : mcycleh_inc[31:0]; rvdffe #(32) mcycleh_ff (.*, .clk(free_l2clk), .en(wr_mcycleh_r | mcyclel_cout_f), .din(mcycleh_ns[31:0]), .dout(mcycleh[31:0])); // ---------------------------------------------------------------------- // MINSTRETL (RW) // [31:0] : Lower Instruction retired count // From the spec "Some CSRs, such as the instructions retired counter, instret, may be modified as side effects // of instruction execution. In these cases, if a CSR access instruction reads a CSR, it reads the // value prior to the execution of the instruction. If a CSR access instruction writes a CSR, the // update occurs after the execution of the instruction. In particular, a value written to instret by // one instruction will be the value read by the following instruction (i.e., the increment of instret // caused by the first instruction retiring happens before the write of the new value)." assign i0_valid_no_ebreak_ecall_r = dec_tlu_i0_valid_r & ~(ebreak_r | ecall_r | ebreak_to_debug_mode_r | illegal_r | mcountinhibit[2]); assign wr_minstretl_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MINSTRETL); assign {minstretl_couta, minstretl_inc[7:0]} = minstretl[7:0] + {7'b0,1'b1}; assign {minstretl_cout, minstretl_inc[31:8]} = minstretl[31:8] + {23'b0, minstretl_couta}; assign minstret_enable = (i0_valid_no_ebreak_ecall_r & tlu_i0_commit_cmt) | wr_minstretl_r; assign minstretl_cout_ns = minstretl_cout & ~wr_minstreth_r & i0_valid_no_ebreak_ecall_r & ~dec_tlu_dbg_halted; assign minstretl_ns[31:0] = wr_minstretl_r ? dec_csr_wrdata_r[31:0] : minstretl_inc[31:0]; rvdffe #(24) minstretl_bff (.*, .en(wr_minstretl_r | (minstretl_couta & minstret_enable)), .din(minstretl_ns[31:8]), .dout(minstretl[31:8])); rvdffe #(8) minstretl_aff (.*, .en(minstret_enable), .din(minstretl_ns[7:0]), .dout(minstretl[7:0])); assign minstretl_read[31:0] = minstretl[31:0]; // ---------------------------------------------------------------------- // MINSTRETH (RW) // [63:32] : Higher Instret count // Chained with minstretl. Note: minstretl overflow due to a minstreth write gets ignored. assign wr_minstreth_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MINSTRETH); assign minstreth_inc[31:0] = minstreth[31:0] + {31'b0, minstretl_cout_f}; assign minstreth_ns[31:0] = wr_minstreth_r ? dec_csr_wrdata_r[31:0] : minstreth_inc[31:0]; rvdffe #(32) minstreth_ff (.*, .en((minstret_enable_f & minstretl_cout_f) | wr_minstreth_r), .din(minstreth_ns[31:0]), .dout(minstreth[31:0])); assign minstreth_read[31:0] = minstreth_inc[31:0]; // ---------------------------------------------------------------------- // MSCRATCH (RW) // [31:0] : Scratch register assign wr_mscratch_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MSCRATCH); rvdffe #(32) mscratch_ff (.*, .en(wr_mscratch_r), .din(dec_csr_wrdata_r[31:0]), .dout(mscratch[31:0])); // ---------------------------------------------------------------------- // MEPC (RW) // [31:1] : Exception PC // NPC assign sel_exu_npc_r = ~dec_tlu_dbg_halted & ~tlu_flush_lower_r_d1 & dec_tlu_i0_valid_r; assign sel_flush_npc_r = ~dec_tlu_dbg_halted & tlu_flush_lower_r_d1 & ~dec_tlu_flush_noredir_r_d1; assign sel_hold_npc_r = ~sel_exu_npc_r & ~sel_flush_npc_r; assign npc_r[31:1] = ( ({31{sel_exu_npc_r}} & exu_npc_r[31:1]) | ({31{~mpc_reset_run_req & reset_delayed}} & rst_vec[31:1]) | // init to reset vector for mpc halt on reset case ({31{(sel_flush_npc_r)}} & tlu_flush_path_r_d1[31:1]) | ({31{(sel_hold_npc_r)}} & npc_r_d1[31:1]) ); rvdffpcie #(31) npwbc_ff (.*, .en(sel_exu_npc_r | sel_flush_npc_r | reset_delayed), .din(npc_r[31:1]), .dout(npc_r_d1[31:1])); // PC has to be captured for exceptions and interrupts. For MRET, we could execute it and then take an // interrupt before the next instruction. assign pc0_valid_r = ~dec_tlu_dbg_halted & dec_tlu_i0_valid_r; assign pc_r[31:1] = ( ({31{ pc0_valid_r}} & dec_tlu_i0_pc_r[31:1]) | ({31{~pc0_valid_r}} & pc_r_d1[31:1])); rvdffpcie #(31) pwbc_ff (.*, .en(pc0_valid_r), .din(pc_r[31:1]), .dout(pc_r_d1[31:1])); assign wr_mepc_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MEPC); assign mepc_ns[31:1] = ( ({31{i0_exception_valid_r | lsu_exc_valid_r | mepc_trigger_hit_sel_pc_r}} & pc_r[31:1]) | ({31{interrupt_valid_r}} & npc_r[31:1]) | ({31{wr_mepc_r & ~exc_or_int_valid_r}} & dec_csr_wrdata_r[31:1]) | ({31{~wr_mepc_r & ~exc_or_int_valid_r}} & mepc[31:1]) ); rvdffe #(31) mepc_ff (.*, .en(i0_exception_valid_r | lsu_exc_valid_r | mepc_trigger_hit_sel_pc_r | interrupt_valid_r | wr_mepc_r), .din(mepc_ns[31:1]), .dout(mepc[31:1])); // ---------------------------------------------------------------------- // MCAUSE (RW) // [31:0] : Exception Cause assign wr_mcause_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MCAUSE); assign mcause_sel_nmi_store = exc_or_int_valid_r & take_nmi & nmi_lsu_store_type; assign mcause_sel_nmi_load = exc_or_int_valid_r & take_nmi & nmi_lsu_load_type; assign mcause_sel_nmi_ext = exc_or_int_valid_r & take_nmi & take_ext_int_start_d3 & |lsu_fir_error[1:0] & ~nmi_int_detected_f; // FIR value decoder // 0 –no error // 1 –uncorrectable ecc => f000_1000 // 2 –dccm region access error => f000_1001 // 3 –non dccm region access error => f000_1002 assign mcause_fir_error_type[1:0] = {&lsu_fir_error[1:0], lsu_fir_error[1] & ~lsu_fir_error[0]}; assign mcause_ns[31:0] = ( ({32{mcause_sel_nmi_store}} & {32'hf000_0000}) | ({32{mcause_sel_nmi_load}} & {32'hf000_0001}) | ({32{mcause_sel_nmi_ext}} & {28'hf000_100, 2'b0, mcause_fir_error_type[1:0]}) | ({32{exc_or_int_valid_r & ~take_nmi}} & {interrupt_valid_r, 26'b0, exc_cause_r[4:0]}) | ({32{wr_mcause_r & ~exc_or_int_valid_r}} & dec_csr_wrdata_r[31:0]) | ({32{~wr_mcause_r & ~exc_or_int_valid_r}} & mcause[31:0]) ); rvdffe #(32) mcause_ff (.*, .en(exc_or_int_valid_r | wr_mcause_r), .din(mcause_ns[31:0]), .dout(mcause[31:0])); // ---------------------------------------------------------------------- // MSCAUSE (RW) // [2:0] : Secondary exception Cause assign wr_mscause_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MSCAUSE); assign ifu_mscause[3:0] = (dec_tlu_packet_r.icaf_type[1:0] == 2'b00) ? 4'b1001 : {2'b00 , dec_tlu_packet_r.icaf_type[1:0]} ; assign mscause_type[3:0] = ( ({4{lsu_i0_exc_r}} & lsu_error_pkt_r.mscause[3:0]) | ({4{i0_trigger_hit_r}} & 4'b0001) | ({4{ebreak_r}} & 4'b0010) | ({4{inst_acc_r}} & ifu_mscause[3:0]) ); assign mscause_ns[3:0] = ( ({4{exc_or_int_valid_r}} & mscause_type[3:0]) | ({4{ wr_mscause_r & ~exc_or_int_valid_r}} & dec_csr_wrdata_r[3:0]) | ({4{~wr_mscause_r & ~exc_or_int_valid_r}} & mscause[3:0]) ); rvdff #(4) mscause_ff (.*, .clk(e4e5_int_clk), .din(mscause_ns[3:0]), .dout(mscause[3:0])); // ---------------------------------------------------------------------- // MTVAL (RW) // [31:0] : Exception address if relevant assign wr_mtval_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTVAL); assign mtval_capture_pc_r = exc_or_int_valid_r & (ebreak_r | (inst_acc_r & ~inst_acc_second_r) | mepc_trigger_hit_sel_pc_r) & ~take_nmi; assign mtval_capture_pc_plus2_r = exc_or_int_valid_r & (inst_acc_r & inst_acc_second_r) & ~take_nmi; assign mtval_capture_inst_r = exc_or_int_valid_r & illegal_r & ~take_nmi; assign mtval_capture_lsu_r = exc_or_int_valid_r & lsu_exc_valid_r & ~take_nmi; assign mtval_clear_r = exc_or_int_valid_r & ~mtval_capture_pc_r & ~mtval_capture_inst_r & ~mtval_capture_lsu_r & ~mepc_trigger_hit_sel_pc_r; assign mtval_ns[31:0] = (({32{mtval_capture_pc_r}} & {pc_r[31:1], 1'b0}) | ({32{mtval_capture_pc_plus2_r}} & {pc_r[31:1] + 31'b1, 1'b0}) | ({32{mtval_capture_inst_r}} & dec_illegal_inst[31:0]) | ({32{mtval_capture_lsu_r}} & lsu_error_pkt_addr_r[31:0]) | ({32{wr_mtval_r & ~interrupt_valid_r}} & dec_csr_wrdata_r[31:0]) | ({32{~take_nmi & ~wr_mtval_r & ~mtval_capture_pc_r & ~mtval_capture_inst_r & ~mtval_clear_r & ~mtval_capture_lsu_r}} & mtval[31:0]) ); rvdffe #(32) mtval_ff (.*, .en(tlu_flush_lower_r | wr_mtval_r), .din(mtval_ns[31:0]), .dout(mtval[31:0])); // ---------------------------------------------------------------------- // MSECCFG // [31:3] : Reserved, read 0x0 // [2] : RLB // [1] : MMWP // [0] : MML `ifdef RV_USER_MODE localparam MSECCFG = 12'h747; localparam MSECCFGH = 12'h757; // Detect if any PMP region is locked regardless of being enabled. This is // necessary for mseccfg.RLB bit write behavior logic [pt.PMP_ENTRIES-1:0] pmp_region_locked; for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_regions assign pmp_region_locked[r] = pmp_pmpcfg[r].lock; end logic pmp_any_region_locked; assign pmp_any_region_locked = |pmp_region_locked; // mseccfg assign wr_mseccfg_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MSECCFG); rvdffs #(3) mseccfg_ff (.*, .clk(csr_wr_clk), .en(wr_mseccfg_r), .din(mseccfg_ns), .dout(mseccfg)); assign mseccfg_ns = { pmp_any_region_locked ? (dec_csr_wrdata_r[MSECCFG_RLB] & mseccfg[MSECCFG_RLB]) : // When any PMP region is locked this bit can only be cleared dec_csr_wrdata_r[MSECCFG_RLB], // Otherwise regularly writeable dec_csr_wrdata_r[MSECCFG_MMWP] | mseccfg[MSECCFG_MMWP], // Sticky bit, can only be set but not cleared dec_csr_wrdata_r[MSECCFG_MML ] | mseccfg[MSECCFG_MML ] // Sticky bit, can only be set but never cleared }; `endif // ---------------------------------------------------------------------- // MCGC (RW) Clock gating control // [31:10]: Reserved, reads 0x0 // [9] : picio_clk_override // [7] : dec_clk_override // [6] : Unused // [5] : ifu_clk_override // [4] : lsu_clk_override // [3] : bus_clk_override // [2] : pic_clk_override // [1] : dccm_clk_override // [0] : icm_clk_override // assign wr_mcgc_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MCGC); assign mcgc_ns[9:0] = wr_mcgc_r ? {~dec_csr_wrdata_r[9], dec_csr_wrdata_r[8:0]} : mcgc_int[9:0]; rvdffe #(10) mcgc_ff (.*, .en(wr_mcgc_r), .din(mcgc_ns[9:0]), .dout(mcgc_int[9:0])); assign mcgc[9:0] = {~mcgc_int[9], mcgc_int[8:0]}; assign dec_tlu_picio_clk_override= mcgc[9]; assign dec_tlu_misc_clk_override = mcgc[8]; assign dec_tlu_dec_clk_override = mcgc[7]; //sign dec_tlu_exu_clk_override = mcgc[6]; assign dec_tlu_ifu_clk_override = mcgc[5]; assign dec_tlu_lsu_clk_override = mcgc[4]; assign dec_tlu_bus_clk_override = mcgc[3]; assign dec_tlu_pic_clk_override = mcgc[2]; assign dec_tlu_dccm_clk_override = mcgc[1]; assign dec_tlu_icm_clk_override = mcgc[0]; // ---------------------------------------------------------------------- // MFDC (RW) Feature Disable Control // [31:19] : Reserved, reads 0x0 // [18:16] : DMA QoS Prty // [15:13] : Reserved, reads 0x0 // [12] : Disable trace // [11] : Disable external load forwarding // [10] : Disable dual issue // [9] : Disable pic multiple ints // [8] : Disable core ecc // [7] : Disable secondary alu?s // [6] : Unused, 0x0 // [5] : Disable non-blocking loads/divides // [4] : Disable fast divide // [3] : Disable branch prediction and return stack // [2] : Disable write buffer coalescing // [1] : Disable load misses that bypass the write buffer // [0] : Disable pipelining - Enable single instruction execution // assign wr_mfdc_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MFDC); rvdffe #(16) mfdc_ff (.*, .en(wr_mfdc_r), .din({mfdc_ns[15:0]}), .dout(mfdc_int[15:0])); // flip poweron value of bit 6 for AXI build if(pt.BUILD_AXI4==1) begin : axi4 // flip poweron valid of bit 12 assign mfdc_ns[15:0] = {~dec_csr_wrdata_r[18:16], dec_csr_wrdata_r[12], dec_csr_wrdata_r[11:7], ~dec_csr_wrdata_r[6], dec_csr_wrdata_r[5:0]}; assign mfdc[18:0] = {~mfdc_int[15:13], 3'b0, mfdc_int[12], mfdc_int[11:7], ~mfdc_int[6], mfdc_int[5:0]}; end else begin // flip poweron valid of bit 12 assign mfdc_ns[15:0] = {~dec_csr_wrdata_r[18:16],dec_csr_wrdata_r[12:0]}; assign mfdc[18:0] = {~mfdc_int[15:13], 3'b0, mfdc_int[12:0]}; end assign dec_tlu_dma_qos_prty[2:0] = mfdc[18:16]; assign dec_tlu_trace_disable = mfdc[12]; assign dec_tlu_external_ldfwd_disable = mfdc[11]; assign dec_tlu_core_ecc_disable = mfdc[8]; assign dec_tlu_sideeffect_posted_disable = mfdc[6]; assign dec_tlu_bpred_disable = mfdc[3]; assign dec_tlu_wb_coalescing_disable = mfdc[2]; assign dec_tlu_pipelining_disable = mfdc[0]; // ---------------------------------------------------------------------- // MCPC (RW) Pause counter // [31:0] : Reads 0x0, decs in the wb register in decode_ctl assign dec_tlu_wr_pause_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MCPC) & ~interrupt_valid_r & ~take_ext_int_start; // ---------------------------------------------------------------------- // MRAC (RW) // [31:0] : Region Access Control Register, 16 regions, {side_effect, cachable} pairs assign wr_mrac_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MRAC); // prevent pairs of 0x11, side_effect and cacheable assign mrac_in[31:0] = {dec_csr_wrdata_r[31], dec_csr_wrdata_r[30] & ~dec_csr_wrdata_r[31], dec_csr_wrdata_r[29], dec_csr_wrdata_r[28] & ~dec_csr_wrdata_r[29], dec_csr_wrdata_r[27], dec_csr_wrdata_r[26] & ~dec_csr_wrdata_r[27], dec_csr_wrdata_r[25], dec_csr_wrdata_r[24] & ~dec_csr_wrdata_r[25], dec_csr_wrdata_r[23], dec_csr_wrdata_r[22] & ~dec_csr_wrdata_r[23], dec_csr_wrdata_r[21], dec_csr_wrdata_r[20] & ~dec_csr_wrdata_r[21], dec_csr_wrdata_r[19], dec_csr_wrdata_r[18] & ~dec_csr_wrdata_r[19], dec_csr_wrdata_r[17], dec_csr_wrdata_r[16] & ~dec_csr_wrdata_r[17], dec_csr_wrdata_r[15], dec_csr_wrdata_r[14] & ~dec_csr_wrdata_r[15], dec_csr_wrdata_r[13], dec_csr_wrdata_r[12] & ~dec_csr_wrdata_r[13], dec_csr_wrdata_r[11], dec_csr_wrdata_r[10] & ~dec_csr_wrdata_r[11], dec_csr_wrdata_r[9], dec_csr_wrdata_r[8] & ~dec_csr_wrdata_r[9], dec_csr_wrdata_r[7], dec_csr_wrdata_r[6] & ~dec_csr_wrdata_r[7], dec_csr_wrdata_r[5], dec_csr_wrdata_r[4] & ~dec_csr_wrdata_r[5], dec_csr_wrdata_r[3], dec_csr_wrdata_r[2] & ~dec_csr_wrdata_r[3], dec_csr_wrdata_r[1], dec_csr_wrdata_r[0] & ~dec_csr_wrdata_r[1]}; rvdffe #(32) mrac_ff (.*, .en(wr_mrac_r), .din(mrac_in[31:0]), .dout(mrac[31:0])); // drive to LSU/IFU assign dec_tlu_mrac_ff[31:0] = mrac[31:0]; // ---------------------------------------------------------------------- // MDEAU (WAR0) // [31:0] : Dbus Error Address Unlock register // assign wr_mdeau_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MDEAU); // ---------------------------------------------------------------------- // MDSEAC (R) // [31:0] : Dbus Store Error Address Capture register // // only capture error bus if the MDSEAC reg is not locked assign mdseac_locked_ns = mdseac_en | (mdseac_locked_f & ~wr_mdeau_r); assign mdseac_en = (lsu_imprecise_error_store_any | lsu_imprecise_error_load_any) & ~nmi_int_detected_f & ~mdseac_locked_f; rvdffe #(32) mdseac_ff (.*, .en(mdseac_en), .din(lsu_imprecise_error_addr_any[31:0]), .dout(mdseac[31:0])); // ---------------------------------------------------------------------- // MPMC (R0W1) // [0] : FW halt // [1] : Set MSTATUS[MIE] on halt assign wr_mpmc_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MPMC); // allow the cycle of the dbg halt flush that contains the wr_mpmc_r to // set the mstatus bit potentially, use delayed version of internal dbg halt. assign fw_halt_req = wr_mpmc_r & dec_csr_wrdata_r[0] & ~internal_dbg_halt_mode_f2 & ~ext_int_freeze_d1; assign fw_halted_ns = (fw_halt_req | fw_halted) & ~set_mie_pmu_fw_halt; assign mpmc_b_ns[1] = wr_mpmc_r ? ~dec_csr_wrdata_r[1] : ~mpmc[1]; rvdff #(1) mpmc_ff (.*, .clk(csr_wr_clk), .din(mpmc_b_ns[1]), .dout(mpmc_b[1])); assign mpmc[1] = ~mpmc_b[1]; // ---------------------------------------------------------------------- // MICECT (I-Cache error counter/threshold) // [31:27] : Icache parity error threshold // [26:0] : Icache parity error count assign csr_sat[31:27] = (dec_csr_wrdata_r[31:27] > 5'd26) ? 5'd26 : dec_csr_wrdata_r[31:27]; assign wr_micect_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MICECT); assign micect_inc[26:0] = micect[26:0] + {26'b0, ic_perr_r}; assign micect_ns = wr_micect_r ? {csr_sat[31:27], dec_csr_wrdata_r[26:0]} : {micect[31:27], micect_inc[26:0]}; rvdffe #(32) micect_ff (.*, .en(wr_micect_r | ic_perr_r), .din(micect_ns[31:0]), .dout(micect[31:0])); assign mice_ce_req = |({32'hffffffff << micect[31:27]} & {5'b0, micect[26:0]}); // ---------------------------------------------------------------------- // MICCMECT (ICCM error counter/threshold) // [31:27] : ICCM parity error threshold // [26:0] : ICCM parity error count assign wr_miccmect_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MICCMECT); assign miccmect_inc[26:0] = miccmect[26:0] + {26'b0, iccm_sbecc_r | iccm_dma_sb_error}; assign miccmect_ns = wr_miccmect_r ? {csr_sat[31:27], dec_csr_wrdata_r[26:0]} : {miccmect[31:27], miccmect_inc[26:0]}; rvdffe #(32) miccmect_ff (.*, .clk(free_l2clk), .en(wr_miccmect_r | iccm_sbecc_r | iccm_dma_sb_error), .din(miccmect_ns[31:0]), .dout(miccmect[31:0])); assign miccme_ce_req = |({32'hffffffff << miccmect[31:27]} & {5'b0, miccmect[26:0]}); // ---------------------------------------------------------------------- // MDCCMECT (DCCM error counter/threshold) // [31:27] : DCCM parity error threshold // [26:0] : DCCM parity error count assign wr_mdccmect_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MDCCMECT); assign mdccmect_inc[26:0] = mdccmect[26:0] + {26'b0, lsu_single_ecc_error_r_d1}; assign mdccmect_ns = wr_mdccmect_r ? {csr_sat[31:27], dec_csr_wrdata_r[26:0]} : {mdccmect[31:27], mdccmect_inc[26:0]}; rvdffe #(32) mdccmect_ff (.*, .clk(free_l2clk), .en(wr_mdccmect_r | lsu_single_ecc_error_r_d1), .din(mdccmect_ns[31:0]), .dout(mdccmect[31:0])); assign mdccme_ce_req = |({32'hffffffff << mdccmect[31:27]} & {5'b0, mdccmect[26:0]}); // ---------------------------------------------------------------------- // MFDHT (Force Debug Halt Threshold) // [5:1] : Halt timeout threshold (power of 2) // [0] : Halt timeout enabled assign wr_mfdht_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MFDHT); assign mfdht_ns[5:0] = wr_mfdht_r ? dec_csr_wrdata_r[5:0] : mfdht[5:0]; rvdffs #(6) mfdht_ff (.*, .clk(csr_wr_clk), .en(wr_mfdht_r), .din(mfdht_ns[5:0]), .dout(mfdht[5:0])); // ---------------------------------------------------------------------- // MFDHS(RW) // [1] : LSU operation pending when debug halt threshold reached // [0] : IFU operation pending when debug halt threshold reached assign wr_mfdhs_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MFDHS); assign mfdhs_ns[1:0] = wr_mfdhs_r ? dec_csr_wrdata_r[1:0] : ((dbg_tlu_halted & ~dbg_tlu_halted_f) ? {~lsu_idle_any_f, ~ifu_miss_state_idle_f} : mfdhs[1:0]); rvdffs #(2) mfdhs_ff (.*, .clk(free_clk), .en(wr_mfdhs_r | dbg_tlu_halted), .din(mfdhs_ns[1:0]), .dout(mfdhs[1:0])); assign force_halt_ctr[31:0] = debug_halt_req_f ? (force_halt_ctr_f[31:0] + 32'b1) : (dbg_tlu_halted_f ? 32'b0 : force_halt_ctr_f[31:0]); rvdffe #(32) forcehaltctr_ff (.*, .en(mfdht[0]), .din(force_halt_ctr[31:0]), .dout(force_halt_ctr_f[31:0])); assign force_halt = mfdht[0] & |(force_halt_ctr_f[31:0] & (32'hffffffff << mfdht[5:1])); // ---------------------------------------------------------------------- // MEIVT (External Interrupt Vector Table (R/W)) // [31:10]: Base address (R/W) // [9:0] : Reserved, reads 0x0 assign wr_meivt_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MEIVT); rvdffe #(22) meivt_ff (.*, .en(wr_meivt_r), .din(dec_csr_wrdata_r[31:10]), .dout(meivt[31:10])); // ---------------------------------------------------------------------- // MEIHAP (External Interrupt Handler Access Pointer (R)) // [31:10]: Base address (R/W) // [9:2] : ClaimID (R) // [1:0] : Reserved, 0x0 assign wr_meihap_r = wr_meicpct_r; rvdffe #(8) meihap_ff (.*, .en(wr_meihap_r), .din(pic_claimid[7:0]), .dout(meihap[9:2])); assign dec_tlu_meihap[31:2] = {meivt[31:10], meihap[9:2]}; // ---------------------------------------------------------------------- // MEICURPL (R/W) // [31:4] : Reserved (read 0x0) // [3:0] : CURRPRI - Priority level of current interrupt service routine (R/W) assign wr_meicurpl_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MEICURPL); assign meicurpl_ns[3:0] = wr_meicurpl_r ? dec_csr_wrdata_r[3:0] : meicurpl[3:0]; rvdff #(4) meicurpl_ff (.*, .clk(csr_wr_clk), .din(meicurpl_ns[3:0]), .dout(meicurpl[3:0])); // PIC needs this reg assign dec_tlu_meicurpl[3:0] = meicurpl[3:0]; // ---------------------------------------------------------------------- // MEICIDPL (R/W) // [31:4] : Reserved (read 0x0) // [3:0] : External Interrupt Claim ID's Priority Level Register assign wr_meicidpl_r = (dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MEICIDPL)) | take_ext_int_start; assign meicidpl_ns[3:0] = wr_meicpct_r ? pic_pl[3:0] : (wr_meicidpl_r ? dec_csr_wrdata_r[3:0] : meicidpl[3:0]); // ---------------------------------------------------------------------- // MEICPCT (Capture CLAIMID in MEIHAP and PL in MEICIDPL // [31:1] : Reserved (read 0x0) // [0] : Capture (W1, Read 0) assign wr_meicpct_r = (dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MEICPCT)) | take_ext_int_start; // ---------------------------------------------------------------------- // MEIPT (External Interrupt Priority Threshold) // [31:4] : Reserved (read 0x0) // [3:0] : PRITHRESH assign wr_meipt_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MEIPT); assign meipt_ns[3:0] = wr_meipt_r ? dec_csr_wrdata_r[3:0] : meipt[3:0]; rvdff #(4) meipt_ff (.*, .clk(csr_wr_clk), .din(meipt_ns[3:0]), .dout(meipt[3:0])); // to PIC assign dec_tlu_meipt[3:0] = meipt[3:0]; // ---------------------------------------------------------------------- // DCSR (R/W) (Only accessible in debug mode) // [31:28] : xdebugver (hard coded to 0x4) RO // [27:16] : 0x0, reserved // [15] : ebreakm // [14] : 0x0, reserved // [13] : ebreaks (0x0 for this core) // [12] : ebreaku (0x0 for this core) // [11] : stepie // [10] : stopcount // [9] : 0x0 //stoptime // [8:6] : cause (RO) // [5:4] : 0x0, reserved // [3] : nmip // [2] : step // [1:0] : prv (0x3 for this core) // // RV has clarified that 'priority 4' in the spec means top priority. // 4. single step. 3. Debugger request. 2. Ebreak. 1. Trigger. // RV debug spec indicates a cause priority change for trigger hits during single step. assign trigger_hit_for_dscr_cause_r_d1 = trigger_hit_dmode_r_d1 | (trigger_hit_r_d1 & dcsr_single_step_done_f); assign dcsr_cause[8:6] = ( ({3{dcsr_single_step_done_f & ~ebreak_to_debug_mode_r_d1 & ~trigger_hit_for_dscr_cause_r_d1 & ~debug_halt_req}} & 3'b100) | ({3{debug_halt_req & ~ebreak_to_debug_mode_r_d1 & ~trigger_hit_for_dscr_cause_r_d1}} & 3'b011) | ({3{ebreak_to_debug_mode_r_d1 & ~trigger_hit_for_dscr_cause_r_d1}} & 3'b001) | ({3{trigger_hit_for_dscr_cause_r_d1}} & 3'b010)); assign wr_dcsr_r = allow_dbg_halt_csr_write & dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == DCSR); // Multiple halt enter requests can happen before we are halted. // We have to continue to upgrade based on dcsr_cause priority but we can't downgrade. assign dcsr_cause_upgradeable = internal_dbg_halt_mode_f & (dcsr[8:6] == 3'b011); assign enter_debug_halt_req_le = enter_debug_halt_req & (~dbg_tlu_halted | dcsr_cause_upgradeable); assign nmi_in_debug_mode = nmi_int_detected_f & internal_dbg_halt_mode_f; assign dcsr_ns[15:2] = enter_debug_halt_req_le ? {dcsr[15:9], dcsr_cause[8:6], dcsr[5:2]} : (wr_dcsr_r ? {dec_csr_wrdata_r[15], 3'b0, dec_csr_wrdata_r[11:10], 1'b0, dcsr[8:6], 2'b00, nmi_in_debug_mode | dcsr[3], dec_csr_wrdata_r[2]} : {dcsr[15:4], nmi_in_debug_mode, dcsr[2]}); rvdffe #(14) dcsr_ff (.*, .clk(free_l2clk), .en(enter_debug_halt_req_le | wr_dcsr_r | internal_dbg_halt_mode | take_nmi), .din(dcsr_ns[15:2]), .dout(dcsr[15:2])); // ---------------------------------------------------------------------- // DPC (R/W) (Only accessible in debug mode) // [31:0] : Debug PC assign wr_dpc_r = allow_dbg_halt_csr_write & dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == DPC); assign dpc_capture_npc = dbg_tlu_halted & ~dbg_tlu_halted_f & ~request_debug_mode_done; assign dpc_capture_pc = request_debug_mode_r; assign dpc_ns[31:1] = ( ({31{~dpc_capture_pc & ~dpc_capture_npc & wr_dpc_r}} & dec_csr_wrdata_r[31:1]) | ({31{dpc_capture_pc}} & pc_r[31:1]) | ({31{~dpc_capture_pc & dpc_capture_npc}} & npc_r[31:1]) ); rvdffe #(31) dpc_ff (.*, .en(wr_dpc_r | dpc_capture_pc | dpc_capture_npc), .din(dpc_ns[31:1]), .dout(dpc[31:1])); // ---------------------------------------------------------------------- // DICAWICS (R/W) (Only accessible in debug mode) // [31:25] : Reserved // [24] : Array select, 0 is data, 1 is tag // [23:22] : Reserved // [21:20] : Way select // [19:17] : Reserved // [16:3] : Index // [2:0] : Reserved assign dicawics_ns[16:0] = {dec_csr_wrdata_r[24], dec_csr_wrdata_r[21:20], dec_csr_wrdata_r[16:3]}; assign wr_dicawics_r = allow_dbg_halt_csr_write & dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == DICAWICS); rvdffe #(17) dicawics_ff (.*, .en(wr_dicawics_r), .din(dicawics_ns[16:0]), .dout(dicawics[16:0])); // ---------------------------------------------------------------------- // DICAD0 (R/W) (Only accessible in debug mode) // // If dicawics[array] is 0 // [31:0] : inst data // // If dicawics[array] is 1 // [31:16] : Tag // [15:7] : Reserved // [6:4] : LRU // [3:1] : Reserved // [0] : Valid assign dicad0_ns[31:0] = wr_dicad0_r ? dec_csr_wrdata_r[31:0] : ifu_ic_debug_rd_data[31:0]; assign wr_dicad0_r = allow_dbg_halt_csr_write & dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == DICAD0); rvdffe #(32) dicad0_ff (.*, .en(wr_dicad0_r | ifu_ic_debug_rd_data_valid), .din(dicad0_ns[31:0]), .dout(dicad0[31:0])); // ---------------------------------------------------------------------- // DICAD0H (R/W) (Only accessible in debug mode) // // If dicawics[array] is 0 // [63:32] : inst data // assign dicad0h_ns[31:0] = wr_dicad0h_r ? dec_csr_wrdata_r[31:0] : ifu_ic_debug_rd_data[63:32]; assign wr_dicad0h_r = allow_dbg_halt_csr_write & dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == DICAD0H); rvdffe #(32) dicad0h_ff (.*, .en(wr_dicad0h_r | ifu_ic_debug_rd_data_valid), .din(dicad0h_ns[31:0]), .dout(dicad0h[31:0])); if (pt.ICACHE_ECC == 1) begin : genblock1 // ---------------------------------------------------------------------- // DICAD1 (R/W) (Only accessible in debug mode) // [6:0] : ECC localparam DICAD1 = 12'h7ca; assign dicad1_ns[6:0] = wr_dicad1_r ? dec_csr_wrdata_r[6:0] : ifu_ic_debug_rd_data[70:64]; assign wr_dicad1_r = allow_dbg_halt_csr_write & dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == DICAD1); rvdffe #(.WIDTH(7), .OVERRIDE(1)) dicad1_ff (.*, .en(wr_dicad1_r | ifu_ic_debug_rd_data_valid), .din(dicad1_ns[6:0]), .dout(dicad1_raw[6:0])); assign dicad1[31:0] = {25'b0, dicad1_raw[6:0]}; end else begin : genblock1 // ---------------------------------------------------------------------- // DICAD1 (R/W) (Only accessible in debug mode) // [3:0] : Parity localparam DICAD1 = 12'h7ca; assign dicad1_ns[3:0] = wr_dicad1_r ? dec_csr_wrdata_r[3:0] : ifu_ic_debug_rd_data[67:64]; assign wr_dicad1_r = allow_dbg_halt_csr_write & dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == DICAD1); rvdffs #(4) dicad1_ff (.*, .clk(free_clk), .en(wr_dicad1_r | ifu_ic_debug_rd_data_valid), .din(dicad1_ns[3:0]), .dout(dicad1_raw[3:0])); assign dicad1[31:0] = {28'b0, dicad1_raw[3:0]}; end // ---------------------------------------------------------------------- // DICAGO (R/W) (Only accessible in debug mode) // [0] : Go if (pt.ICACHE_ECC == 1) assign dec_tlu_ic_diag_pkt.icache_wrdata[70:0] = { dicad1[6:0], dicad0h[31:0], dicad0[31:0]}; else assign dec_tlu_ic_diag_pkt.icache_wrdata[70:0] = {3'b0, dicad1[3:0], dicad0h[31:0], dicad0[31:0]}; assign dec_tlu_ic_diag_pkt.icache_dicawics[16:0] = dicawics[16:0]; assign icache_rd_valid = allow_dbg_halt_csr_write & dec_csr_any_unq_d & dec_i0_decode_d & ~dec_csr_wen_unq_d & (dec_csr_rdaddr_d[11:0] == DICAGO); assign icache_wr_valid = allow_dbg_halt_csr_write & dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == DICAGO); assign dec_tlu_ic_diag_pkt.icache_rd_valid = icache_rd_valid_f; assign dec_tlu_ic_diag_pkt.icache_wr_valid = icache_wr_valid_f; // ---------------------------------------------------------------------- // MTSEL (R/W) // [1:0] : Trigger select : 00, 01, 10 are data/address triggers. 11 is inst count assign wr_mtsel_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTSEL); assign mtsel_ns[1:0] = wr_mtsel_r ? {dec_csr_wrdata_r[1:0]} : mtsel[1:0]; rvdff #(2) mtsel_ff (.*, .clk(csr_wr_clk), .din(mtsel_ns[1:0]), .dout(mtsel[1:0])); // ---------------------------------------------------------------------- // MTDATA1 (R/W) // [31:0] : Trigger Data 1 // for triggers 0, 1, 2 and 3 aka Match Control // [31:28] : type, hard coded to 0x2 // [27] : dmode // [26:21] : hard coded to 0x1f // [20] : hit // [19] : select (0 - address, 1 - data) // [18] : timing, always 'before', reads 0x0 // [17:12] : action, bits [17:13] not implemented and reads 0x0 // [11] : chain // [10:7] : match, bits [10:8] not implemented and reads 0x0 // [6] : M // [5:3] : not implemented, reads 0x0 // [2] : execute // [1] : store // [0] : load // // decoder ring // [27] : => 9 // [20] : => 8 // [19] : => 7 // [12] : => 6 // [11] : => 5 // [7] : => 4 // [6] : => 3 // [2] : => 2 // [1] : => 1 // [0] : => 0 // don't allow setting load-data. assign tdata_load = dec_csr_wrdata_r[0] & ~dec_csr_wrdata_r[19]; // don't allow setting execute-data. assign tdata_opcode = dec_csr_wrdata_r[2] & ~dec_csr_wrdata_r[19]; // don't allow clearing DMODE and action=1 assign tdata_action = (dec_csr_wrdata_r[27] & dbg_tlu_halted_f) & dec_csr_wrdata_r[12]; // Chain bit has conditions: WARL for triggers without chains. Force to zero if dmode is 0 but next trigger dmode is 1. assign tdata_chain = mtsel[0] ? 1'b0 : // triggers 1 and 3 chain bit is always zero mtsel[1] ? dec_csr_wrdata_r[11] & ~(mtdata1_t3[MTDATA1_DMODE] & ~dec_csr_wrdata_r[27]) : // trigger 2 dec_csr_wrdata_r[11] & ~(mtdata1_t1[MTDATA1_DMODE] & ~dec_csr_wrdata_r[27]); // trigger 0 // Kill mtdata1 write if dmode=1 but prior trigger has dmode=0/chain=1. Only applies to T1 and T3 assign tdata_kill_write = mtsel[1] ? dec_csr_wrdata_r[27] & (~mtdata1_t2[MTDATA1_DMODE] & mtdata1_t2[MTDATA1_CHAIN]) : // trigger 3 dec_csr_wrdata_r[27] & (~mtdata1_t0[MTDATA1_DMODE] & mtdata1_t0[MTDATA1_CHAIN]) ; // trigger 1 assign tdata_wrdata_r[9:0] = {dec_csr_wrdata_r[27] & dbg_tlu_halted_f, dec_csr_wrdata_r[20:19], tdata_action, tdata_chain, dec_csr_wrdata_r[7:6], tdata_opcode, dec_csr_wrdata_r[1], tdata_load}; // If the DMODE bit is set, tdata1 can only be updated in debug_mode assign wr_mtdata1_t0_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTDATA1) & (mtsel[1:0] == 2'b0) & (~mtdata1_t0[MTDATA1_DMODE] | dbg_tlu_halted_f); assign mtdata1_t0_ns[9:0] = wr_mtdata1_t0_r ? tdata_wrdata_r[9:0] : {mtdata1_t0[9], update_hit_bit_r[0] | mtdata1_t0[8], mtdata1_t0[7:0]}; assign wr_mtdata1_t1_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTDATA1) & (mtsel[1:0] == 2'b01) & (~mtdata1_t1[MTDATA1_DMODE] | dbg_tlu_halted_f) & ~tdata_kill_write; assign mtdata1_t1_ns[9:0] = wr_mtdata1_t1_r ? tdata_wrdata_r[9:0] : {mtdata1_t1[9], update_hit_bit_r[1] | mtdata1_t1[8], mtdata1_t1[7:0]}; assign wr_mtdata1_t2_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTDATA1) & (mtsel[1:0] == 2'b10) & (~mtdata1_t2[MTDATA1_DMODE] | dbg_tlu_halted_f); assign mtdata1_t2_ns[9:0] = wr_mtdata1_t2_r ? tdata_wrdata_r[9:0] : {mtdata1_t2[9], update_hit_bit_r[2] | mtdata1_t2[8], mtdata1_t2[7:0]}; assign wr_mtdata1_t3_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTDATA1) & (mtsel[1:0] == 2'b11) & (~mtdata1_t3[MTDATA1_DMODE] | dbg_tlu_halted_f) & ~tdata_kill_write; assign mtdata1_t3_ns[9:0] = wr_mtdata1_t3_r ? tdata_wrdata_r[9:0] : {mtdata1_t3[9], update_hit_bit_r[3] | mtdata1_t3[8], mtdata1_t3[7:0]}; rvdffe #(10) mtdata1_t0_ff (.*, .en(trigger_enabled[0] | wr_mtdata1_t0_r), .din(mtdata1_t0_ns[9:0]), .dout(mtdata1_t0[9:0])); rvdffe #(10) mtdata1_t1_ff (.*, .en(trigger_enabled[1] | wr_mtdata1_t1_r), .din(mtdata1_t1_ns[9:0]), .dout(mtdata1_t1[9:0])); rvdffe #(10) mtdata1_t2_ff (.*, .en(trigger_enabled[2] | wr_mtdata1_t2_r), .din(mtdata1_t2_ns[9:0]), .dout(mtdata1_t2[9:0])); rvdffe #(10) mtdata1_t3_ff (.*, .en(trigger_enabled[3] | wr_mtdata1_t3_r), .din(mtdata1_t3_ns[9:0]), .dout(mtdata1_t3[9:0])); assign mtdata1_tsel_out[31:0] = ( ({32{(mtsel[1:0] == 2'b00)}} & {4'h2, mtdata1_t0[9], 6'b011111, mtdata1_t0[8:7], 6'b0, mtdata1_t0[6:5], 3'b0, mtdata1_t0[4:3], 3'b0, mtdata1_t0[2:0]}) | ({32{(mtsel[1:0] == 2'b01)}} & {4'h2, mtdata1_t1[9], 6'b011111, mtdata1_t1[8:7], 6'b0, mtdata1_t1[6:5], 3'b0, mtdata1_t1[4:3], 3'b0, mtdata1_t1[2:0]}) | ({32{(mtsel[1:0] == 2'b10)}} & {4'h2, mtdata1_t2[9], 6'b011111, mtdata1_t2[8:7], 6'b0, mtdata1_t2[6:5], 3'b0, mtdata1_t2[4:3], 3'b0, mtdata1_t2[2:0]}) | ({32{(mtsel[1:0] == 2'b11)}} & {4'h2, mtdata1_t3[9], 6'b011111, mtdata1_t3[8:7], 6'b0, mtdata1_t3[6:5], 3'b0, mtdata1_t3[4:3], 3'b0, mtdata1_t3[2:0]})); assign trigger_pkt_any[0].select = mtdata1_t0[MTDATA1_SEL]; assign trigger_pkt_any[0].match = mtdata1_t0[MTDATA1_MATCH]; assign trigger_pkt_any[0].store = mtdata1_t0[MTDATA1_ST]; assign trigger_pkt_any[0].load = mtdata1_t0[MTDATA1_LD]; assign trigger_pkt_any[0].execute = mtdata1_t0[MTDATA1_EXE]; assign trigger_pkt_any[0].m = mtdata1_t0[MTDATA1_M_ENABLED]; assign trigger_pkt_any[1].select = mtdata1_t1[MTDATA1_SEL]; assign trigger_pkt_any[1].match = mtdata1_t1[MTDATA1_MATCH]; assign trigger_pkt_any[1].store = mtdata1_t1[MTDATA1_ST]; assign trigger_pkt_any[1].load = mtdata1_t1[MTDATA1_LD]; assign trigger_pkt_any[1].execute = mtdata1_t1[MTDATA1_EXE]; assign trigger_pkt_any[1].m = mtdata1_t1[MTDATA1_M_ENABLED]; assign trigger_pkt_any[2].select = mtdata1_t2[MTDATA1_SEL]; assign trigger_pkt_any[2].match = mtdata1_t2[MTDATA1_MATCH]; assign trigger_pkt_any[2].store = mtdata1_t2[MTDATA1_ST]; assign trigger_pkt_any[2].load = mtdata1_t2[MTDATA1_LD]; assign trigger_pkt_any[2].execute = mtdata1_t2[MTDATA1_EXE]; assign trigger_pkt_any[2].m = mtdata1_t2[MTDATA1_M_ENABLED]; assign trigger_pkt_any[3].select = mtdata1_t3[MTDATA1_SEL]; assign trigger_pkt_any[3].match = mtdata1_t3[MTDATA1_MATCH]; assign trigger_pkt_any[3].store = mtdata1_t3[MTDATA1_ST]; assign trigger_pkt_any[3].load = mtdata1_t3[MTDATA1_LD]; assign trigger_pkt_any[3].execute = mtdata1_t3[MTDATA1_EXE]; assign trigger_pkt_any[3].m = mtdata1_t3[MTDATA1_M_ENABLED]; // ---------------------------------------------------------------------- // MTDATA2 (R/W) // [31:0] : Trigger Data 2 // If the DMODE bit is set, tdata2 can only be updated in debug_mode assign wr_mtdata2_t0_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTDATA2) & (mtsel[1:0] == 2'b0) & (~mtdata1_t0[MTDATA1_DMODE] | dbg_tlu_halted_f); assign wr_mtdata2_t1_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTDATA2) & (mtsel[1:0] == 2'b01) & (~mtdata1_t1[MTDATA1_DMODE] | dbg_tlu_halted_f); assign wr_mtdata2_t2_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTDATA2) & (mtsel[1:0] == 2'b10) & (~mtdata1_t2[MTDATA1_DMODE] | dbg_tlu_halted_f); assign wr_mtdata2_t3_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MTDATA2) & (mtsel[1:0] == 2'b11) & (~mtdata1_t3[MTDATA1_DMODE] | dbg_tlu_halted_f); rvdffe #(32) mtdata2_t0_ff (.*, .en(wr_mtdata2_t0_r), .din(dec_csr_wrdata_r[31:0]), .dout(mtdata2_t0[31:0])); rvdffe #(32) mtdata2_t1_ff (.*, .en(wr_mtdata2_t1_r), .din(dec_csr_wrdata_r[31:0]), .dout(mtdata2_t1[31:0])); rvdffe #(32) mtdata2_t2_ff (.*, .en(wr_mtdata2_t2_r), .din(dec_csr_wrdata_r[31:0]), .dout(mtdata2_t2[31:0])); rvdffe #(32) mtdata2_t3_ff (.*, .en(wr_mtdata2_t3_r), .din(dec_csr_wrdata_r[31:0]), .dout(mtdata2_t3[31:0])); assign mtdata2_tsel_out[31:0] = ( ({32{(mtsel[1:0] == 2'b00)}} & mtdata2_t0[31:0]) | ({32{(mtsel[1:0] == 2'b01)}} & mtdata2_t1[31:0]) | ({32{(mtsel[1:0] == 2'b10)}} & mtdata2_t2[31:0]) | ({32{(mtsel[1:0] == 2'b11)}} & mtdata2_t3[31:0])); assign trigger_pkt_any[0].tdata2[31:0] = mtdata2_t0[31:0]; assign trigger_pkt_any[1].tdata2[31:0] = mtdata2_t1[31:0]; assign trigger_pkt_any[2].tdata2[31:0] = mtdata2_t2[31:0]; assign trigger_pkt_any[3].tdata2[31:0] = mtdata2_t3[31:0]; //---------------------------------------------------------------------- // Performance Monitor Counters section starts //---------------------------------------------------------------------- localparam MHPME_NOEVENT = 10'd0; localparam MHPME_CLK_ACTIVE = 10'd1; // OOP - out of pipe localparam MHPME_ICACHE_HIT = 10'd2; // OOP localparam MHPME_ICACHE_MISS = 10'd3; // OOP localparam MHPME_INST_COMMIT = 10'd4; localparam MHPME_INST_COMMIT_16B = 10'd5; localparam MHPME_INST_COMMIT_32B = 10'd6; localparam MHPME_INST_ALIGNED = 10'd7; // OOP localparam MHPME_INST_DECODED = 10'd8; // OOP localparam MHPME_INST_MUL = 10'd9; localparam MHPME_INST_DIV = 10'd10; localparam MHPME_INST_LOAD = 10'd11; localparam MHPME_INST_STORE = 10'd12; localparam MHPME_INST_MALOAD = 10'd13; localparam MHPME_INST_MASTORE = 10'd14; localparam MHPME_INST_ALU = 10'd15; localparam MHPME_INST_CSRREAD = 10'd16; localparam MHPME_INST_CSRRW = 10'd17; localparam MHPME_INST_CSRWRITE = 10'd18; localparam MHPME_INST_EBREAK = 10'd19; localparam MHPME_INST_ECALL = 10'd20; localparam MHPME_INST_FENCE = 10'd21; localparam MHPME_INST_FENCEI = 10'd22; localparam MHPME_INST_MRET = 10'd23; localparam MHPME_INST_BRANCH = 10'd24; localparam MHPME_BRANCH_MP = 10'd25; localparam MHPME_BRANCH_TAKEN = 10'd26; localparam MHPME_BRANCH_NOTP = 10'd27; localparam MHPME_FETCH_STALL = 10'd28; // OOP localparam MHPME_DECODE_STALL = 10'd30; // OOP localparam MHPME_POSTSYNC_STALL = 10'd31; // OOP localparam MHPME_PRESYNC_STALL = 10'd32; // OOP localparam MHPME_LSU_SB_WB_STALL = 10'd34; // OOP localparam MHPME_DMA_DCCM_STALL = 10'd35; // OOP localparam MHPME_DMA_ICCM_STALL = 10'd36; // OOP localparam MHPME_EXC_TAKEN = 10'd37; localparam MHPME_TIMER_INT_TAKEN = 10'd38; localparam MHPME_EXT_INT_TAKEN = 10'd39; localparam MHPME_FLUSH_LOWER = 10'd40; localparam MHPME_BR_ERROR = 10'd41; localparam MHPME_IBUS_TRANS = 10'd42; // OOP localparam MHPME_DBUS_TRANS = 10'd43; // OOP localparam MHPME_DBUS_MA_TRANS = 10'd44; // OOP localparam MHPME_IBUS_ERROR = 10'd45; // OOP localparam MHPME_DBUS_ERROR = 10'd46; // OOP localparam MHPME_IBUS_STALL = 10'd47; // OOP localparam MHPME_DBUS_STALL = 10'd48; // OOP localparam MHPME_INT_DISABLED = 10'd49; // OOP localparam MHPME_INT_STALLED = 10'd50; // OOP localparam MHPME_INST_BITMANIP = 10'd54; localparam MHPME_DBUS_LOAD = 10'd55; localparam MHPME_DBUS_STORE = 10'd56; // Counts even during sleep state localparam MHPME_SLEEP_CYC = 10'd512; // OOP localparam MHPME_DMA_READ_ALL = 10'd513; // OOP localparam MHPME_DMA_WRITE_ALL = 10'd514; // OOP localparam MHPME_DMA_READ_DCCM = 10'd515; // OOP localparam MHPME_DMA_WRITE_DCCM = 10'd516; // OOP // Pack the event selects into a vector for genvar assign mhpme_vec[0][9:0] = mhpme3[9:0]; assign mhpme_vec[1][9:0] = mhpme4[9:0]; assign mhpme_vec[2][9:0] = mhpme5[9:0]; assign mhpme_vec[3][9:0] = mhpme6[9:0]; // only consider committed itypes //logic [3:0] pmu_i0_itype_qual; assign pmu_i0_itype_qual[3:0] = dec_tlu_packet_r.pmu_i0_itype[3:0] & {4{tlu_i0_commit_cmt}}; // Generate the muxed incs for all counters based on event type for (genvar i=0 ; i < 4; i++) begin assign mhpmc_inc_r[i] = {{~mcountinhibit[i+3]}} & ( ({1{(mhpme_vec[i][9:0] == MHPME_CLK_ACTIVE )}} & 1'b1) | ({1{(mhpme_vec[i][9:0] == MHPME_ICACHE_HIT )}} & {ifu_pmu_ic_hit}) | ({1{(mhpme_vec[i][9:0] == MHPME_ICACHE_MISS )}} & {ifu_pmu_ic_miss}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_COMMIT )}} & {tlu_i0_commit_cmt & ~illegal_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_COMMIT_16B )}} & {tlu_i0_commit_cmt & ~exu_pmu_i0_pc4 & ~illegal_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_COMMIT_32B )}} & {tlu_i0_commit_cmt & exu_pmu_i0_pc4 & ~illegal_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_ALIGNED )}} & ifu_pmu_instr_aligned) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_DECODED )}} & dec_pmu_instr_decoded) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_MUL )}} & {(pmu_i0_itype_qual == MUL)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_DIV )}} & {dec_tlu_packet_r.pmu_divide & tlu_i0_commit_cmt & ~illegal_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_LOAD )}} & {(pmu_i0_itype_qual == LOAD)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_STORE )}} & {(pmu_i0_itype_qual == STORE)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_MALOAD )}} & {(pmu_i0_itype_qual == LOAD)} & {1{dec_tlu_packet_r.pmu_lsu_misaligned}}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_MASTORE )}} & {(pmu_i0_itype_qual == STORE)} & {1{dec_tlu_packet_r.pmu_lsu_misaligned}}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_ALU )}} & {(pmu_i0_itype_qual == ALU)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_CSRREAD )}} & {(pmu_i0_itype_qual == CSRREAD)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_CSRWRITE )}} & {(pmu_i0_itype_qual == CSRWRITE)})| ({1{(mhpme_vec[i][9:0] == MHPME_INST_CSRRW )}} & {(pmu_i0_itype_qual == CSRRW)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_EBREAK )}} & {(pmu_i0_itype_qual == EBREAK)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_ECALL )}} & {(pmu_i0_itype_qual == ECALL)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_FENCE )}} & {(pmu_i0_itype_qual == FENCE)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_FENCEI )}} & {(pmu_i0_itype_qual == FENCEI)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_MRET )}} & {(pmu_i0_itype_qual == MRET)}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_BRANCH )}} & { ((pmu_i0_itype_qual == CONDBR) | (pmu_i0_itype_qual == JAL))}) | ({1{(mhpme_vec[i][9:0] == MHPME_BRANCH_MP )}} & {exu_pmu_i0_br_misp & tlu_i0_commit_cmt & ~illegal_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_BRANCH_TAKEN )}} & {exu_pmu_i0_br_ataken & tlu_i0_commit_cmt & ~illegal_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_BRANCH_NOTP )}} & {dec_tlu_packet_r.pmu_i0_br_unpred & tlu_i0_commit_cmt & ~illegal_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_FETCH_STALL )}} & { ifu_pmu_fetch_stall}) | ({1{(mhpme_vec[i][9:0] == MHPME_DECODE_STALL )}} & { dec_pmu_decode_stall}) | ({1{(mhpme_vec[i][9:0] == MHPME_POSTSYNC_STALL )}} & {dec_pmu_postsync_stall}) | ({1{(mhpme_vec[i][9:0] == MHPME_PRESYNC_STALL )}} & {dec_pmu_presync_stall}) | ({1{(mhpme_vec[i][9:0] == MHPME_LSU_SB_WB_STALL )}} & { lsu_store_stall_any}) | ({1{(mhpme_vec[i][9:0] == MHPME_DMA_DCCM_STALL )}} & { dma_dccm_stall_any}) | ({1{(mhpme_vec[i][9:0] == MHPME_DMA_ICCM_STALL )}} & { dma_iccm_stall_any}) | ({1{(mhpme_vec[i][9:0] == MHPME_EXC_TAKEN )}} & { (i0_exception_valid_r | i0_trigger_hit_r | lsu_exc_valid_r)}) | ({1{(mhpme_vec[i][9:0] == MHPME_TIMER_INT_TAKEN )}} & { take_timer_int | take_int_timer0_int | take_int_timer1_int}) | ({1{(mhpme_vec[i][9:0] == MHPME_EXT_INT_TAKEN )}} & { take_ext_int}) | ({1{(mhpme_vec[i][9:0] == MHPME_FLUSH_LOWER )}} & { tlu_flush_lower_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_BR_ERROR )}} & {(dec_tlu_br0_error_r | dec_tlu_br0_start_error_r) & rfpc_i0_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_IBUS_TRANS )}} & {ifu_pmu_bus_trxn}) | ({1{(mhpme_vec[i][9:0] == MHPME_DBUS_TRANS )}} & {lsu_pmu_bus_trxn}) | ({1{(mhpme_vec[i][9:0] == MHPME_DBUS_MA_TRANS )}} & {lsu_pmu_bus_misaligned}) | ({1{(mhpme_vec[i][9:0] == MHPME_IBUS_ERROR )}} & {ifu_pmu_bus_error}) | ({1{(mhpme_vec[i][9:0] == MHPME_DBUS_ERROR )}} & {lsu_pmu_bus_error}) | ({1{(mhpme_vec[i][9:0] == MHPME_IBUS_STALL )}} & {ifu_pmu_bus_busy}) | ({1{(mhpme_vec[i][9:0] == MHPME_DBUS_STALL )}} & {lsu_pmu_bus_busy}) | ({1{(mhpme_vec[i][9:0] == MHPME_INT_DISABLED )}} & {~mstatus[MSTATUS_MIE]}) | ({1{(mhpme_vec[i][9:0] == MHPME_INT_STALLED )}} & {~mstatus[MSTATUS_MIE] & |(mip[5:0] & mie[5:0])}) | ({1{(mhpme_vec[i][9:0] == MHPME_INST_BITMANIP )}} & {(pmu_i0_itype_qual == BITMANIPU)}) | ({1{(mhpme_vec[i][9:0] == MHPME_DBUS_LOAD )}} & {tlu_i0_commit_cmt & lsu_pmu_load_external_r & ~illegal_r}) | ({1{(mhpme_vec[i][9:0] == MHPME_DBUS_STORE )}} & {tlu_i0_commit_cmt & lsu_pmu_store_external_r & ~illegal_r}) | // These count even during sleep ({1{(mhpme_vec[i][9:0] == MHPME_SLEEP_CYC )}} & {dec_tlu_pmu_fw_halted}) | ({1{(mhpme_vec[i][9:0] == MHPME_DMA_READ_ALL )}} & {dma_pmu_any_read}) | ({1{(mhpme_vec[i][9:0] == MHPME_DMA_WRITE_ALL )}} & {dma_pmu_any_write}) | ({1{(mhpme_vec[i][9:0] == MHPME_DMA_READ_DCCM )}} & {dma_pmu_dccm_read}) | ({1{(mhpme_vec[i][9:0] == MHPME_DMA_WRITE_DCCM )}} & {dma_pmu_dccm_write}) ); end if(pt.FAST_INTERRUPT_REDIRECT) begin : genblock2 `ifdef RV_USER_MODE rvdffie #(33) mstatus_ff (.*, .clk(free_l2clk), .din({mdseac_locked_ns, lsu_single_ecc_error_r, lsu_exc_valid_r, lsu_i0_exc_r, take_ext_int_start, take_ext_int_start_d1, take_ext_int_start_d2, ext_int_freeze, mip_ns[5:0], mcyclel_cout & ~wr_mcycleh_r & mcyclel_cout_in, minstret_enable, minstretl_cout_ns, fw_halted_ns, meicidpl_ns[3:0], icache_rd_valid, icache_wr_valid, mhpmc_inc_r[3:0], perfcnt_halted, mstatus_ns[3:0]}), .dout({mdseac_locked_f, lsu_single_ecc_error_r_d1, lsu_exc_valid_r_d1, lsu_i0_exc_r_d1, take_ext_int_start_d1, take_ext_int_start_d2, take_ext_int_start_d3, ext_int_freeze_d1, mip[5:0], mcyclel_cout_f, minstret_enable_f, minstretl_cout_f, fw_halted, meicidpl[3:0], icache_rd_valid_f, icache_wr_valid_f, mhpmc_inc_r_d1[3:0], perfcnt_halted_d1, mstatus[3:0]})); `else rvdffie #(31) mstatus_ff (.*, .clk(free_l2clk), .din({mdseac_locked_ns, lsu_single_ecc_error_r, lsu_exc_valid_r, lsu_i0_exc_r, take_ext_int_start, take_ext_int_start_d1, take_ext_int_start_d2, ext_int_freeze, mip_ns[5:0], mcyclel_cout & ~wr_mcycleh_r & mcyclel_cout_in, minstret_enable, minstretl_cout_ns, fw_halted_ns, meicidpl_ns[3:0], icache_rd_valid, icache_wr_valid, mhpmc_inc_r[3:0], perfcnt_halted, mstatus_ns[1:0]}), .dout({mdseac_locked_f, lsu_single_ecc_error_r_d1, lsu_exc_valid_r_d1, lsu_i0_exc_r_d1, take_ext_int_start_d1, take_ext_int_start_d2, take_ext_int_start_d3, ext_int_freeze_d1, mip[5:0], mcyclel_cout_f, minstret_enable_f, minstretl_cout_f, fw_halted, meicidpl[3:0], icache_rd_valid_f, icache_wr_valid_f, mhpmc_inc_r_d1[3:0], perfcnt_halted_d1, mstatus[1:0]})); `endif end else begin : genblock2 `ifdef RV_USER_MODE rvdffie #(29) mstatus_ff (.*, .clk(free_l2clk), .din({mdseac_locked_ns, lsu_single_ecc_error_r, lsu_exc_valid_r, lsu_i0_exc_r, mip_ns[5:0], mcyclel_cout & ~wr_mcycleh_r & mcyclel_cout_in, minstret_enable, minstretl_cout_ns, fw_halted_ns, meicidpl_ns[3:0], icache_rd_valid, icache_wr_valid, mhpmc_inc_r[3:0], perfcnt_halted, mstatus_ns[3:0]}), .dout({mdseac_locked_f, lsu_single_ecc_error_r_d1, lsu_exc_valid_r_d1, lsu_i0_exc_r_d1, mip[5:0], mcyclel_cout_f, minstret_enable_f, minstretl_cout_f, fw_halted, meicidpl[3:0], icache_rd_valid_f, icache_wr_valid_f, mhpmc_inc_r_d1[3:0], perfcnt_halted_d1, mstatus[3:0]})); `else rvdffie #(27) mstatus_ff (.*, .clk(free_l2clk), .din({mdseac_locked_ns, lsu_single_ecc_error_r, lsu_exc_valid_r, lsu_i0_exc_r, mip_ns[5:0], mcyclel_cout & ~wr_mcycleh_r & mcyclel_cout_in, minstret_enable, minstretl_cout_ns, fw_halted_ns, meicidpl_ns[3:0], icache_rd_valid, icache_wr_valid, mhpmc_inc_r[3:0], perfcnt_halted, mstatus_ns[1:0]}), .dout({mdseac_locked_f, lsu_single_ecc_error_r_d1, lsu_exc_valid_r_d1, lsu_i0_exc_r_d1, mip[5:0], mcyclel_cout_f, minstret_enable_f, minstretl_cout_f, fw_halted, meicidpl[3:0], icache_rd_valid_f, icache_wr_valid_f, mhpmc_inc_r_d1[3:0], perfcnt_halted_d1, mstatus[1:0]})); `endif end assign perfcnt_halted = ((dec_tlu_dbg_halted & dcsr[DCSR_STOPC]) | dec_tlu_pmu_fw_halted); assign perfcnt_during_sleep[3:0] = {4{~(dec_tlu_dbg_halted & dcsr[DCSR_STOPC])}} & {mhpme_vec[3][9],mhpme_vec[2][9],mhpme_vec[1][9],mhpme_vec[0][9]}; assign dec_tlu_perfcnt0 = mhpmc_inc_r_d1[0] & ~(perfcnt_halted_d1 & ~perfcnt_during_sleep[0]); assign dec_tlu_perfcnt1 = mhpmc_inc_r_d1[1] & ~(perfcnt_halted_d1 & ~perfcnt_during_sleep[1]); assign dec_tlu_perfcnt2 = mhpmc_inc_r_d1[2] & ~(perfcnt_halted_d1 & ~perfcnt_during_sleep[2]); assign dec_tlu_perfcnt3 = mhpmc_inc_r_d1[3] & ~(perfcnt_halted_d1 & ~perfcnt_during_sleep[3]); // ---------------------------------------------------------------------- // MHPMC3H(RW), MHPMC3(RW) // [63:32][31:0] : Hardware Performance Monitor Counter 3 assign mhpmc3_wr_en0 = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPMC3); assign mhpmc3_wr_en1 = (~perfcnt_halted | perfcnt_during_sleep[0]) & (|(mhpmc_inc_r[0])); assign mhpmc3_wr_en = mhpmc3_wr_en0 | mhpmc3_wr_en1; assign mhpmc3_incr[63:0] = {mhpmc3h[31:0],mhpmc3[31:0]} + {63'b0, 1'b1}; assign mhpmc3_ns[31:0] = mhpmc3_wr_en0 ? dec_csr_wrdata_r[31:0] : mhpmc3_incr[31:0]; rvdffe #(32) mhpmc3_ff (.*, .clk(free_l2clk), .en(mhpmc3_wr_en), .din(mhpmc3_ns[31:0]), .dout(mhpmc3[31:0])); assign mhpmc3h_wr_en0 = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPMC3H); assign mhpmc3h_wr_en = mhpmc3h_wr_en0 | mhpmc3_wr_en1; assign mhpmc3h_ns[31:0] = mhpmc3h_wr_en0 ? dec_csr_wrdata_r[31:0] : mhpmc3_incr[63:32]; rvdffe #(32) mhpmc3h_ff (.*, .clk(free_l2clk), .en(mhpmc3h_wr_en), .din(mhpmc3h_ns[31:0]), .dout(mhpmc3h[31:0])); // ---------------------------------------------------------------------- // MHPMC4H(RW), MHPMC4(RW) // [63:32][31:0] : Hardware Performance Monitor Counter 4 assign mhpmc4_wr_en0 = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPMC4); assign mhpmc4_wr_en1 = (~perfcnt_halted | perfcnt_during_sleep[1]) & (|(mhpmc_inc_r[1])); assign mhpmc4_wr_en = mhpmc4_wr_en0 | mhpmc4_wr_en1; assign mhpmc4_incr[63:0] = {mhpmc4h[31:0],mhpmc4[31:0]} + {63'b0,1'b1}; assign mhpmc4_ns[31:0] = mhpmc4_wr_en0 ? dec_csr_wrdata_r[31:0] : mhpmc4_incr[31:0]; rvdffe #(32) mhpmc4_ff (.*, .clk(free_l2clk), .en(mhpmc4_wr_en), .din(mhpmc4_ns[31:0]), .dout(mhpmc4[31:0])); assign mhpmc4h_wr_en0 = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPMC4H); assign mhpmc4h_wr_en = mhpmc4h_wr_en0 | mhpmc4_wr_en1; assign mhpmc4h_ns[31:0] = mhpmc4h_wr_en0 ? dec_csr_wrdata_r[31:0] : mhpmc4_incr[63:32]; rvdffe #(32) mhpmc4h_ff (.*, .clk(free_l2clk), .en(mhpmc4h_wr_en), .din(mhpmc4h_ns[31:0]), .dout(mhpmc4h[31:0])); // ---------------------------------------------------------------------- // MHPMC5H(RW), MHPMC5(RW) // [63:32][31:0] : Hardware Performance Monitor Counter 5 assign mhpmc5_wr_en0 = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPMC5); assign mhpmc5_wr_en1 = (~perfcnt_halted | perfcnt_during_sleep[2]) & (|(mhpmc_inc_r[2])); assign mhpmc5_wr_en = mhpmc5_wr_en0 | mhpmc5_wr_en1; assign mhpmc5_incr[63:0] = {mhpmc5h[31:0],mhpmc5[31:0]} + {63'b0,1'b1}; assign mhpmc5_ns[31:0] = mhpmc5_wr_en0 ? dec_csr_wrdata_r[31:0] : mhpmc5_incr[31:0]; rvdffe #(32) mhpmc5_ff (.*, .clk(free_l2clk), .en(mhpmc5_wr_en), .din(mhpmc5_ns[31:0]), .dout(mhpmc5[31:0])); assign mhpmc5h_wr_en0 = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPMC5H); assign mhpmc5h_wr_en = mhpmc5h_wr_en0 | mhpmc5_wr_en1; assign mhpmc5h_ns[31:0] = mhpmc5h_wr_en0 ? dec_csr_wrdata_r[31:0] : mhpmc5_incr[63:32]; rvdffe #(32) mhpmc5h_ff (.*, .clk(free_l2clk), .en(mhpmc5h_wr_en), .din(mhpmc5h_ns[31:0]), .dout(mhpmc5h[31:0])); // ---------------------------------------------------------------------- // MHPMC6H(RW), MHPMC6(RW) // [63:32][31:0] : Hardware Performance Monitor Counter 6 assign mhpmc6_wr_en0 = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPMC6); assign mhpmc6_wr_en1 = (~perfcnt_halted | perfcnt_during_sleep[3]) & (|(mhpmc_inc_r[3])); assign mhpmc6_wr_en = mhpmc6_wr_en0 | mhpmc6_wr_en1; assign mhpmc6_incr[63:0] = {mhpmc6h[31:0],mhpmc6[31:0]} + {63'b0,1'b1}; assign mhpmc6_ns[31:0] = mhpmc6_wr_en0 ? dec_csr_wrdata_r[31:0] : mhpmc6_incr[31:0]; rvdffe #(32) mhpmc6_ff (.*, .clk(free_l2clk), .en(mhpmc6_wr_en), .din(mhpmc6_ns[31:0]), .dout(mhpmc6[31:0])); assign mhpmc6h_wr_en0 = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPMC6H); assign mhpmc6h_wr_en = mhpmc6h_wr_en0 | mhpmc6_wr_en1; assign mhpmc6h_ns[31:0] = mhpmc6h_wr_en0 ? dec_csr_wrdata_r[31:0] : mhpmc6_incr[63:32]; rvdffe #(32) mhpmc6h_ff (.*, .clk(free_l2clk), .en(mhpmc6h_wr_en), .din(mhpmc6h_ns[31:0]), .dout(mhpmc6h[31:0])); // ---------------------------------------------------------------------- // MHPME3(RW) // [9:0] : Hardware Performance Monitor Event 3 // we only have events 0-56 with holes, 512-516, HPME* are WARL so zero otherwise. assign zero_event_r = ( (dec_csr_wrdata_r[9:0] > 10'd516) | (|dec_csr_wrdata_r[31:10]) | ((dec_csr_wrdata_r[9:0] < 10'd512) & (dec_csr_wrdata_r[9:0] > 10'd56)) | ((dec_csr_wrdata_r[9:0] < 10'd54) & (dec_csr_wrdata_r[9:0] > 10'd50)) | (dec_csr_wrdata_r[9:0] == 10'd29) | (dec_csr_wrdata_r[9:0] == 10'd33) ); assign event_r[9:0] = zero_event_r ? '0 : dec_csr_wrdata_r[9:0]; assign wr_mhpme3_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPME3); rvdffe #(10) mhpme3_ff (.*, .en(wr_mhpme3_r), .din(event_r[9:0]), .dout(mhpme3[9:0])); // ---------------------------------------------------------------------- // MHPME4(RW) // [9:0] : Hardware Performance Monitor Event 4 assign wr_mhpme4_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPME4); rvdffe #(10) mhpme4_ff (.*, .en(wr_mhpme4_r), .din(event_r[9:0]), .dout(mhpme4[9:0])); // ---------------------------------------------------------------------- // MHPME5(RW) // [9:0] : Hardware Performance Monitor Event 5 assign wr_mhpme5_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPME5); rvdffe #(10) mhpme5_ff (.*, .en(wr_mhpme5_r), .din(event_r[9:0]), .dout(mhpme5[9:0])); // ---------------------------------------------------------------------- // MHPME6(RW) // [9:0] : Hardware Performance Monitor Event 6 assign wr_mhpme6_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MHPME6); rvdffe #(10) mhpme6_ff (.*, .en(wr_mhpme6_r), .din(event_r[9:0]), .dout(mhpme6[9:0])); //---------------------------------------------------------------------- // Performance Monitor Counters section ends //---------------------------------------------------------------------- // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // MCOUNTEREN // [31:3] : Reserved, read 0x0 // [2] : INSTRET user-mode access disable // [1] : reserved, read 0x0 // [0] : CYCLE user-mode access disable `ifdef RV_USER_MODE localparam MCOUNTEREN = 12'h306; assign wr_mcounteren_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MCOUNTEREN); rvdffs #(6) mcounteren_ff (.*, .clk(csr_wr_clk), .en(wr_mcounteren_r), .din({dec_csr_wrdata_r[6:2], dec_csr_wrdata_r[0]}), .dout(mcounteren)); `endif // MCOUNTINHIBIT(RW) // [31:7] : Reserved, read 0x0 // [6] : HPM6 disable // [5] : HPM5 disable // [4] : HPM4 disable // [3] : HPM3 disable // [2] : MINSTRET disable // [1] : reserved, read 0x0 // [0] : MCYCLE disable assign wr_mcountinhibit_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MCOUNTINHIBIT); rvdffs #(6) mcountinhibit_ff (.*, .clk(csr_wr_clk), .en(wr_mcountinhibit_r), .din({dec_csr_wrdata_r[6:2], dec_csr_wrdata_r[0]}), .dout({mcountinhibit[6:2], mcountinhibit[0]})); assign mcountinhibit[1] = 1'b0; //-------------------------------------------------------------------------------- // trace //-------------------------------------------------------------------------------- logic [4:0] dec_tlu_exc_cause_wb1_raw, dec_tlu_exc_cause_wb2; logic dec_tlu_int_valid_wb1_raw, dec_tlu_int_valid_wb2; assign {dec_tlu_i0_valid_wb1, dec_tlu_i0_exc_valid_wb1, dec_tlu_exc_cause_wb1_raw[4:0], dec_tlu_int_valid_wb1_raw} = {8{~dec_tlu_trace_disable}} & {i0_valid_wb, i0_exception_valid_r_d1 | lsu_i0_exc_r_d1 | (trigger_hit_r_d1 & ~trigger_hit_dmode_r_d1), exc_cause_wb[4:0], interrupt_valid_r_d1}; // skid buffer for ints, reduces trace port count by 1 rvdffie #(.WIDTH(6), .OVERRIDE(1)) traceskidff (.*, .clk(clk), .din ({dec_tlu_exc_cause_wb1_raw[4:0], dec_tlu_int_valid_wb1_raw}), .dout({dec_tlu_exc_cause_wb2[4:0], dec_tlu_int_valid_wb2})); //skid for ints assign dec_tlu_exc_cause_wb1[4:0] = dec_tlu_int_valid_wb2 ? dec_tlu_exc_cause_wb2[4:0] : dec_tlu_exc_cause_wb1_raw[4:0]; assign dec_tlu_int_valid_wb1 = dec_tlu_int_valid_wb2; assign dec_tlu_mtval_wb1 = mtval[31:0]; // end trace //-------------------------------------------------------------------------------- // ---------------------------------------------------------------------- // CSR read mux // ---------------------------------------------------------------------- assign dec_tlu_presync_d = presync & dec_csr_any_unq_d & ~dec_csr_wen_unq_d; assign dec_tlu_postsync_d = postsync & dec_csr_any_unq_d; // allow individual configuration of these features assign conditionally_illegal = ((csr_mitcnt0 | csr_mitcnt1 | csr_mitb0 | csr_mitb1 | csr_mitctl0 | csr_mitctl1) & ~|pt.TIMER_LEGAL_EN); assign valid_csr = ( legal & (~(csr_dcsr | csr_dpc | csr_dmst | csr_dicawics | csr_dicad0 | csr_dicad0h | csr_dicad1 | csr_dicago) | dbg_tlu_halted_f) & ~fast_int_meicpct & ~conditionally_illegal); assign dec_csr_legal_d = ( dec_csr_any_unq_d & valid_csr & // of a valid CSR ~(dec_csr_wen_unq_d & (csr_mvendorid | csr_marchid | csr_mimpid | csr_mhartid | csr_mdseac | csr_meihap)) // that's not a write to a RO CSR ); // CSR read mux logic [31:0] mstatus_rf, mie_rf, mtvec_rf, mscratch_rf, mepc_rf, mcause_rf, mtval_rf, mip_rf, mcyclel_rf, mcycleh_rf, minstretl_rf, minstreth_rf, mrac_rf; `ifdef RV_USER_MODE assign mstatus_rf = {14'b0, mstatus[MSTATUS_MPRV], 4'b0, ~mstatus[MSTATUS_MPP], ~mstatus[MSTATUS_MPP], 3'b0, mstatus[MSTATUS_MPIE], 3'b0, mstatus[MSTATUS_MIE], 3'b0}; `else assign mstatus_rf = {19'b0, 2'b11, 3'b0, mstatus[MSTATUS_MPIE], 3'b0, mstatus[MSTATUS_MIE], 3'b0}; `endif assign mie_rf = {1'b0, mie[5:3], 16'b0, mie[2], 3'b0, mie[1], 3'b0, mie[0], 3'b0}; assign mtvec_rf = {mtvec[30:1], 1'b0, mtvec[0]}; assign mscratch_rf = mscratch[31:0]; assign mepc_rf = {mepc[31:1], 1'b0}; assign mcause_rf = mcause[31:0]; assign mtval_rf = mtval[31:0]; assign mip_rf = {1'b0, mip[5:3], 16'b0, mip[2], 3'b0, mip[1], 3'b0, mip[0], 3'b0}; assign mcyclel_rf = mcyclel[31:0]; assign mcycleh_rf = mcycleh_inc[31:0]; assign minstretl_rf = minstretl_read[31:0]; assign minstreth_rf = minstreth_read[31:0]; assign mrac_rf = mrac[31:0]; assign dec_csr_rddata_d[31:0] = ( `ifdef RV_USER_MODE ({32{csr_misa}} & 32'h40101104) | `else ({32{csr_misa}} & 32'h40001104) | `endif ({32{csr_mvendorid}} & 32'h00000045) | ({32{csr_marchid}} & 32'h00000010) | ({32{csr_mimpid}} & 32'h4) | ({32{csr_mhartid}} & {core_id[31:4], 4'b0}) | ({32{csr_mstatus}} & mstatus_rf[31:0]) | ({32{csr_mtvec}} & mtvec_rf) | ({32{csr_mip}} & mip_rf) | ({32{csr_mie}} & mie_rf) | ({32{csr_mcyclel}} & mcyclel_rf) | ({32{csr_mcycleh}} & mcycleh_rf) | ({32{csr_minstretl}} & minstretl_rf) | ({32{csr_minstreth}} & minstreth_rf) | ({32{csr_mscratch}} & mscratch_rf) | ({32{csr_mepc}} & mepc_rf) | ({32{csr_mcause}} & mcause_rf) | ({32{csr_mscause}} & {28'b0, mscause[3:0]}) | ({32{csr_mtval}} & mtval_rf) | ({32{csr_mrac}} & mrac_rf) | ({32{csr_mdseac}} & mdseac[31:0]) | ({32{csr_meivt}} & {meivt[31:10], 10'b0}) | ({32{csr_meihap}} & {meivt[31:10], meihap[9:2], 2'b0}) | ({32{csr_meicurpl}} & {28'b0, meicurpl[3:0]}) | ({32{csr_meicidpl}} & {28'b0, meicidpl[3:0]}) | ({32{csr_meipt}} & {28'b0, meipt[3:0]}) | ({32{csr_mcgc}} & {22'b0, mcgc[9:0]}) | ({32{csr_mfdc}} & {13'b0, mfdc[18:0]}) | ({32{csr_dcsr}} & {16'h4000, dcsr[15:2], 2'b11}) | ({32{csr_dpc}} & {dpc[31:1], 1'b0}) | ({32{csr_dicad0}} & dicad0[31:0]) | ({32{csr_dicad0h}} & dicad0h[31:0]) | ({32{csr_dicad1}} & dicad1[31:0]) | ({32{csr_dicawics}} & {7'b0, dicawics[16], 2'b0, dicawics[15:14], 3'b0, dicawics[13:0], 3'b0}) | ({32{csr_mtsel}} & {30'b0, mtsel[1:0]}) | ({32{csr_mtdata1}} & {mtdata1_tsel_out[31:0]}) | ({32{csr_mtdata2}} & {mtdata2_tsel_out[31:0]}) | ({32{csr_micect}} & {micect[31:0]}) | ({32{csr_miccmect}} & {miccmect[31:0]}) | ({32{csr_mdccmect}} & {mdccmect[31:0]}) | ({32{csr_mhpmc3}} & mhpmc3[31:0]) | ({32{csr_mhpmc4}} & mhpmc4[31:0]) | ({32{csr_mhpmc5}} & mhpmc5[31:0]) | ({32{csr_mhpmc6}} & mhpmc6[31:0]) | ({32{csr_mhpmc3h}} & mhpmc3h[31:0]) | ({32{csr_mhpmc4h}} & mhpmc4h[31:0]) | ({32{csr_mhpmc5h}} & mhpmc5h[31:0]) | ({32{csr_mhpmc6h}} & mhpmc6h[31:0]) | ({32{csr_mfdht}} & {26'b0, mfdht[5:0]}) | ({32{csr_mfdhs}} & {30'b0, mfdhs[1:0]}) | ({32{csr_mhpme3}} & {22'b0,mhpme3[9:0]}) | ({32{csr_mhpme4}} & {22'b0,mhpme4[9:0]}) | ({32{csr_mhpme5}} & {22'b0,mhpme5[9:0]}) | ({32{csr_mhpme6}} & {22'b0,mhpme6[9:0]}) | `ifdef RV_USER_MODE ({32{csr_menvcfg}} & 32'd0) | ({32{csr_menvcfgh}} & 32'd0) | ({32{csr_mcounteren}} & {25'b0, mcounteren[5:1], 1'b0, mcounteren[0]}) | ({32{csr_cyclel}} & mcyclel[31:0]) | ({32{csr_cycleh}} & mcycleh_inc[31:0]) | ({32{csr_instretl}} & minstretl_read[31:0]) | ({32{csr_instreth}} & minstreth_read[31:0]) | ({32{csr_hpmc3}} & mhpmc3[31:0]) | ({32{csr_hpmc4}} & mhpmc4[31:0]) | ({32{csr_hpmc5}} & mhpmc5[31:0]) | ({32{csr_hpmc6}} & mhpmc6[31:0]) | ({32{csr_hpmc3h}} & mhpmc3h[31:0]) | ({32{csr_hpmc4h}} & mhpmc4h[31:0]) | ({32{csr_hpmc5h}} & mhpmc5h[31:0]) | ({32{csr_hpmc6h}} & mhpmc6h[31:0]) | ({32{csr_mseccfgl}} & {29'd0, mseccfg}) | ({32{csr_mseccfgh}} & 32'd0) | // All bits are WPRI `endif ({32{csr_mcountinhibit}} & {25'b0, mcountinhibit[6:0]}) | ({32{csr_mpmc}} & {30'b0, mpmc[1], 1'b0}) | ({32{dec_timer_read_d}} & dec_timer_rddata_d[31:0]) | ({32{dec_pmp_read_d}} & dec_pmp_rddata_d[31:0]) ); `ifdef RV_LOCKSTEP_REGFILE_ENABLE // Expose the register file assign regfile.tlu.pc = pc_r; assign regfile.tlu.npc = npc_r; assign regfile.tlu.mstatus = mstatus_rf; assign regfile.tlu.mie = mie_rf; assign regfile.tlu.mtvec = mtvec_rf; assign regfile.tlu.mscratch = mscratch_rf; assign regfile.tlu.mepc = mepc_rf; assign regfile.tlu.mcause = mcause_rf; assign regfile.tlu.mtval = mtval_rf; assign regfile.tlu.mip = mip_rf; assign regfile.tlu.mcyclel = mcyclel_rf; assign regfile.tlu.mcycleh = mcycleh_rf; assign regfile.tlu.minstretl = minstretl_rf; assign regfile.tlu.minstreth = minstreth_rf; assign regfile.tlu.mrac = mrac_rf; `endif endmodule // el2_dec_tlu_ctl module el2_dec_timer_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic free_l2clk, input logic csr_wr_clk, input logic rst_l, input logic dec_csr_wen_r_mod, // csr write enable at wb input logic [11:0] dec_csr_wraddr_r, // write address for csr input logic [31:0] dec_csr_wrdata_r, // csr write data at wb input logic csr_mitctl0, input logic csr_mitctl1, input logic csr_mitb0, input logic csr_mitb1, input logic csr_mitcnt0, input logic csr_mitcnt1, input logic dec_pause_state, // Paused input logic dec_tlu_pmu_fw_halted, // pmu/fw halted input logic internal_dbg_halt_timers, // debug halted output logic [31:0] dec_timer_rddata_d, // timer CSR read data output logic dec_timer_read_d, // timer CSR address match output logic dec_timer_t0_pulse, // timer0 int output logic dec_timer_t1_pulse, // timer1 int // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); localparam MITCTL_ENABLE = 0; localparam MITCTL_ENABLE_HALTED = 1; localparam MITCTL_ENABLE_PAUSED = 2; logic [31:0] mitcnt0_ns, mitcnt0, mitcnt1_ns, mitcnt1, mitb0, mitb1, mitb0_b, mitb1_b, mitcnt0_inc, mitcnt1_inc; logic [2:0] mitctl0_ns, mitctl0; logic [3:0] mitctl1_ns, mitctl1; logic wr_mitcnt0_r, wr_mitcnt1_r, wr_mitb0_r, wr_mitb1_r, wr_mitctl0_r, wr_mitctl1_r; logic mitcnt0_inc_ok, mitcnt1_inc_ok; logic mitcnt0_inc_cout, mitcnt1_inc_cout; logic mit0_match_ns; logic mit1_match_ns; logic mitctl0_0_b_ns; logic mitctl0_0_b; logic mitctl1_0_b_ns; logic mitctl1_0_b; assign mit0_match_ns = (mitcnt0[31:0] >= mitb0[31:0]); assign mit1_match_ns = (mitcnt1[31:0] >= mitb1[31:0]); assign dec_timer_t0_pulse = mit0_match_ns; assign dec_timer_t1_pulse = mit1_match_ns; // ---------------------------------------------------------------------- // MITCNT0 (RW) // [31:0] : Internal Timer Counter 0 localparam MITCNT0 = 12'h7d2; assign wr_mitcnt0_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MITCNT0); assign mitcnt0_inc_ok = mitctl0[MITCTL_ENABLE] & (~dec_pause_state | mitctl0[MITCTL_ENABLE_PAUSED]) & (~dec_tlu_pmu_fw_halted | mitctl0[MITCTL_ENABLE_HALTED]) & ~internal_dbg_halt_timers; assign {mitcnt0_inc_cout, mitcnt0_inc[7:0]} = mitcnt0[7:0] + {7'b0, 1'b1}; assign mitcnt0_inc[31:8] = mitcnt0[31:8] + {23'b0, mitcnt0_inc_cout}; assign mitcnt0_ns[31:0] = wr_mitcnt0_r ? dec_csr_wrdata_r[31:0] : mit0_match_ns ? 'b0 : mitcnt0_inc[31:0]; rvdffe #(24) mitcnt0_ffb (.*, .clk(free_l2clk), .en(wr_mitcnt0_r | (mitcnt0_inc_ok & mitcnt0_inc_cout) | mit0_match_ns), .din(mitcnt0_ns[31:8]), .dout(mitcnt0[31:8])); rvdffe #(8) mitcnt0_ffa (.*, .clk(free_l2clk), .en(wr_mitcnt0_r | mitcnt0_inc_ok | mit0_match_ns), .din(mitcnt0_ns[7:0]), .dout(mitcnt0[7:0])); // ---------------------------------------------------------------------- // MITCNT1 (RW) // [31:0] : Internal Timer Counter 0 localparam MITCNT1 = 12'h7d5; assign wr_mitcnt1_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MITCNT1); assign mitcnt1_inc_ok = mitctl1[MITCTL_ENABLE] & (~dec_pause_state | mitctl1[MITCTL_ENABLE_PAUSED]) & (~dec_tlu_pmu_fw_halted | mitctl1[MITCTL_ENABLE_HALTED]) & ~internal_dbg_halt_timers & (~mitctl1[3] | mit0_match_ns); // only inc MITCNT1 if not cascaded with 0, or if 0 overflows assign {mitcnt1_inc_cout, mitcnt1_inc[7:0]} = mitcnt1[7:0] + {7'b0, 1'b1}; assign mitcnt1_inc[31:8] = mitcnt1[31:8] + {23'b0, mitcnt1_inc_cout}; assign mitcnt1_ns[31:0] = wr_mitcnt1_r ? dec_csr_wrdata_r[31:0] : mit1_match_ns ? 'b0 : mitcnt1_inc[31:0]; rvdffe #(24) mitcnt1_ffb (.*, .clk(free_l2clk), .en(wr_mitcnt1_r | (mitcnt1_inc_ok & mitcnt1_inc_cout) | mit1_match_ns), .din(mitcnt1_ns[31:8]), .dout(mitcnt1[31:8])); rvdffe #(8) mitcnt1_ffa (.*, .clk(free_l2clk), .en(wr_mitcnt1_r | mitcnt1_inc_ok | mit1_match_ns), .din(mitcnt1_ns[7:0]), .dout(mitcnt1[7:0])); // ---------------------------------------------------------------------- // MITB0 (RW) // [31:0] : Internal Timer Bound 0 localparam MITB0 = 12'h7d3; assign wr_mitb0_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MITB0); rvdffe #(32) mitb0_ff (.*, .en(wr_mitb0_r), .din(~dec_csr_wrdata_r[31:0]), .dout(mitb0_b[31:0])); assign mitb0[31:0] = ~mitb0_b[31:0]; // ---------------------------------------------------------------------- // MITB1 (RW) // [31:0] : Internal Timer Bound 1 localparam MITB1 = 12'h7d6; assign wr_mitb1_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MITB1); rvdffe #(32) mitb1_ff (.*, .en(wr_mitb1_r), .din(~dec_csr_wrdata_r[31:0]), .dout(mitb1_b[31:0])); assign mitb1[31:0] = ~mitb1_b[31:0]; // ---------------------------------------------------------------------- // MITCTL0 (RW) Internal Timer Ctl 0 // [31:3] : Reserved, reads 0x0 // [2] : Enable while PAUSEd // [1] : Enable while HALTed // [0] : Enable (resets to 0x1) localparam MITCTL0 = 12'h7d4; assign wr_mitctl0_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MITCTL0); assign mitctl0_ns[2:0] = wr_mitctl0_r ? {dec_csr_wrdata_r[2:0]} : {mitctl0[2:0]}; assign mitctl0_0_b_ns = ~mitctl0_ns[0]; rvdffs #(3) mitctl0_ff (.*, .clk(csr_wr_clk), .en(wr_mitctl0_r), .din({mitctl0_ns[2:1], mitctl0_0_b_ns}), .dout({mitctl0[2:1], mitctl0_0_b})); assign mitctl0[0] = ~mitctl0_0_b; // ---------------------------------------------------------------------- // MITCTL1 (RW) Internal Timer Ctl 1 // [31:4] : Reserved, reads 0x0 // [3] : Cascade // [2] : Enable while PAUSEd // [1] : Enable while HALTed // [0] : Enable (resets to 0x1) localparam MITCTL1 = 12'h7d7; assign wr_mitctl1_r = dec_csr_wen_r_mod & (dec_csr_wraddr_r[11:0] == MITCTL1); assign mitctl1_ns[3:0] = wr_mitctl1_r ? {dec_csr_wrdata_r[3:0]} : {mitctl1[3:0]}; assign mitctl1_0_b_ns = ~mitctl1_ns[0]; rvdffs #(4) mitctl1_ff (.*, .clk(csr_wr_clk), .en(wr_mitctl1_r), .din({mitctl1_ns[3:1], mitctl1_0_b_ns}), .dout({mitctl1[3:1], mitctl1_0_b})); assign mitctl1[0] = ~mitctl1_0_b; assign dec_timer_read_d = csr_mitcnt1 | csr_mitcnt0 | csr_mitb1 | csr_mitb0 | csr_mitctl0 | csr_mitctl1; assign dec_timer_rddata_d[31:0] = ( ({32{csr_mitcnt0}} & mitcnt0[31:0]) | ({32{csr_mitcnt1}} & mitcnt1[31:0]) | ({32{csr_mitb0}} & mitb0[31:0]) | ({32{csr_mitb1}} & mitb1[31:0]) | ({32{csr_mitctl0}} & {29'b0, mitctl0[2:0]}) | ({32{csr_mitctl1}} & {28'b0, mitctl1[3:0]}) ); endmodule // dec_timer_ctl ================================================ FILE: design/dec/el2_dec_trigger.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: DEC Trigger Logic // Comments: // //******************************************************************************** module el2_dec_trigger import el2_pkg::*; #( `include "el2_param.vh" )( input el2_trigger_pkt_t [3:0] trigger_pkt_any, // Packet from tlu. 'select':0-pc,1-Opcode 'Execute' needs to be set for dec triggers to fire. 'match'-1 do mask, 0: full match input logic [31:1] dec_i0_pc_d, // i0 pc output logic [3:0] dec_i0_trigger_match_d // Trigger match ); logic [3:0][31:0] dec_i0_match_data; logic [3:0] dec_i0_trigger_data_match; for (genvar i=0; i<4; i++) begin : genblock assign dec_i0_match_data[i][31:0] = ({32{~trigger_pkt_any[i].select & trigger_pkt_any[i].execute}} & {dec_i0_pc_d[31:1], trigger_pkt_any[i].tdata2[0]}); // select=0; do a PC match rvmaskandmatch trigger_i0_match (.mask(trigger_pkt_any[i].tdata2[31:0]), .data(dec_i0_match_data[i][31:0]), .masken(trigger_pkt_any[i].match), .match(dec_i0_trigger_data_match[i])); assign dec_i0_trigger_match_d[i] = trigger_pkt_any[i].execute & trigger_pkt_any[i].m & dec_i0_trigger_data_match[i]; end endmodule // el2_dec_trigger ================================================ FILE: design/dmi/dmi_jtag_to_core_sync.v ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2018 Western Digital Corporation or it's affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //------------------------------------------------------------------------------------ // // Copyright Western Digital, 2019 // Owner : Alex Grobman // Description: // This module Synchronizes the signals between JTAG (TCK) and // processor (Core_clk) // //------------------------------------------------------------------------------------- module dmi_jtag_to_core_sync ( // JTAG signals input rd_en, // 1 bit Read Enable from JTAG input wr_en, // 1 bit Write enable from JTAG // Processor Signals input rst_n, // Core reset input clk, // Core clock output reg_en, // 1 bit Write interface bit to Processor output reg_wr_en // 1 bit Write enable to Processor ); wire c_rd_en; wire c_wr_en; reg [2:0] rden, wren; // Outputs assign reg_en = c_wr_en | c_rd_en; assign reg_wr_en = c_wr_en; // synchronizers always @ ( posedge clk or negedge rst_n) begin if(!rst_n) begin rden <= '0; wren <= '0; end else begin rden <= {rden[1:0], rd_en}; wren <= {wren[1:0], wr_en}; end end assign c_rd_en = rden[1] & ~rden[2]; assign c_wr_en = wren[1] & ~wren[2]; endmodule ================================================ FILE: design/dmi/dmi_mux.v ================================================ // DMI core aperture ranges from 0x00 to 0x4F. Addresses starting from 0x50 // and above are considered uncore. module dmi_mux ( // Core access enable input wire core_enable, // Uncore access enable input wire uncore_enable, // DMI upstream input wire dmi_en, input wire dmi_wr_en, input wire [ 6:0] dmi_addr, input wire [31:0] dmi_wdata, output wire [31:0] dmi_rdata, // DMI downstream for core output wire dmi_core_en, output wire dmi_core_wr_en, output wire [ 6:0] dmi_core_addr, output wire [31:0] dmi_core_wdata, input wire [31:0] dmi_core_rdata, // DMI downstream for uncore output wire dmi_uncore_en, output wire dmi_uncore_wr_en, output wire [ 6:0] dmi_uncore_addr, output wire [31:0] dmi_uncore_wdata, input wire [31:0] dmi_uncore_rdata ); logic is_uncore_aperture; // Uncore address decoder assign is_uncore_aperture = (dmi_addr[6] & (dmi_addr[5] | dmi_addr[4])); // Core signals assign dmi_core_en = dmi_en & ~is_uncore_aperture & core_enable; assign dmi_core_wr_en = dmi_wr_en & ~is_uncore_aperture & core_enable; assign dmi_core_addr = dmi_addr; assign dmi_core_wdata = dmi_wdata; // Uncore signals assign dmi_uncore_en = dmi_en & is_uncore_aperture & uncore_enable; assign dmi_uncore_wr_en = dmi_wr_en & is_uncore_aperture & uncore_enable; assign dmi_uncore_addr = dmi_addr; assign dmi_uncore_wdata = dmi_wdata; // Read mux assign dmi_rdata = is_uncore_aperture ? dmi_uncore_rdata : dmi_core_rdata; endmodule ================================================ FILE: design/dmi/dmi_wrapper.v ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2018 Western Digital Corporation or it's affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //------------------------------------------------------------------------------------ // // Copyright Western Digital, 2018 // Owner : Anusha Narayanamoorthy // Description: // Wrapper module for JTAG_TAP and DMI synchronizer // //------------------------------------------------------------------------------------- module dmi_wrapper( // JTAG signals input trst_n, // JTAG reset input tck, // JTAG clock input tms, // Test mode select input tdi, // Test Data Input output tdo, // Test Data Output output tdoEnable, // Test Data Output enable // Processor Signals input core_rst_n, // Core reset input core_clk, // Core clock //jtag_id is supposed to be connected to a constant in the top level /* pragma coverage off*/ input [31:1] jtag_id, // JTAG ID /* pragma coverage on*/ input [31:0] rd_data, // 32 bit Read data from Processor output [31:0] reg_wr_data, // 32 bit Write data to Processor output [6:0] reg_wr_addr, // 7 bit reg address to Processor output reg_en, // 1 bit Read enable to Processor output reg_wr_en, // 1 bit Write enable to Processor output dmi_hard_reset ); //Wire Declaration wire rd_en; wire wr_en; wire dmireset; //jtag_tap instantiation rvjtag_tap i_jtag_tap( .trst(trst_n), // dedicated JTAG TRST (active low) pad signal or asynchronous active low power on reset .tck(tck), // dedicated JTAG TCK pad signal .tms(tms), // dedicated JTAG TMS pad signal .tdi(tdi), // dedicated JTAG TDI pad signal .tdo(tdo), // dedicated JTAG TDO pad signal .tdoEnable(tdoEnable), // enable for TDO pad .wr_data(reg_wr_data), // 32 bit Write data .wr_addr(reg_wr_addr), // 7 bit Write address .rd_en(rd_en), // 1 bit read enable .wr_en(wr_en), // 1 bit Write enable .rd_data(rd_data), // 32 bit Read data .rd_status(2'b0), .idle(3'h0), // no need to wait to sample data .dmi_stat(2'b0), // no need to wait or error possible .version(4'h1), // debug spec 0.13 compliant .jtag_id(jtag_id), .dmi_hard_reset(dmi_hard_reset), .dmi_reset(dmireset) ); // dmi_jtag_to_core_sync instantiation dmi_jtag_to_core_sync i_dmi_jtag_to_core_sync( .wr_en(wr_en), // 1 bit Write enable .rd_en(rd_en), // 1 bit Read enable .rst_n(core_rst_n), .clk(core_clk), .reg_en(reg_en), // 1 bit Write interface bit .reg_wr_en(reg_wr_en) // 1 bit Write enable ); endmodule ================================================ FILE: design/dmi/rvjtag_tap.v ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2019 Western Digital Corporation or it's affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License module rvjtag_tap #( parameter AWIDTH = 7 ) ( input trst, input tck, input tms, input tdi, output reg tdo, output tdoEnable, output [31:0] wr_data, output [AWIDTH-1:0] wr_addr, output wr_en, output rd_en, input [31:0] rd_data, /*pragma coverage off*/ input [1:0] rd_status, /*pragma coverage on*/ output reg dmi_reset, output reg dmi_hard_reset, /*pragma coverage off*/ input [2:0] idle, input [1:0] dmi_stat, /*pragma coverage on*/ /* -- revisionCode : 4'h0; -- manufacturersIdCode : 11'h45; -- deviceIdCode : 16'h0001; -- order MSB .. LSB -> [4 bit version or revision] [16 bit part number] [11 bit manufacturer id] [value of 1'b1 in LSB] */ /*pragma coverage off*/ input [31:1] jtag_id, input [3:0] version /*pragma coverage on*/ ); localparam USER_DR_LENGTH = AWIDTH + 34; reg [USER_DR_LENGTH-1:0] sr, nsr, dr; /////////////////////////////////////////////////////// // Tap controller /////////////////////////////////////////////////////// logic[3:0] state, nstate; logic [4:0] ir; wire jtag_reset; wire shift_dr; wire pause_dr; wire update_dr; wire capture_dr; wire shift_ir; wire pause_ir ; wire update_ir ; wire capture_ir; wire[1:0] dr_en; wire devid_sel; wire [5:0] abits; assign abits = AWIDTH[5:0]; localparam TEST_LOGIC_RESET_STATE = 0; localparam RUN_TEST_IDLE_STATE = 1; localparam SELECT_DR_SCAN_STATE = 2; localparam CAPTURE_DR_STATE = 3; localparam SHIFT_DR_STATE = 4; localparam EXIT1_DR_STATE = 5; localparam PAUSE_DR_STATE = 6; localparam EXIT2_DR_STATE = 7; localparam UPDATE_DR_STATE = 8; localparam SELECT_IR_SCAN_STATE = 9; localparam CAPTURE_IR_STATE = 10; localparam SHIFT_IR_STATE = 11; localparam EXIT1_IR_STATE = 12; localparam PAUSE_IR_STATE = 13; localparam EXIT2_IR_STATE = 14; localparam UPDATE_IR_STATE = 15; always_comb begin nstate = state; case(state) TEST_LOGIC_RESET_STATE: nstate = tms ? TEST_LOGIC_RESET_STATE : RUN_TEST_IDLE_STATE; RUN_TEST_IDLE_STATE: nstate = tms ? SELECT_DR_SCAN_STATE : RUN_TEST_IDLE_STATE; SELECT_DR_SCAN_STATE: nstate = tms ? SELECT_IR_SCAN_STATE : CAPTURE_DR_STATE; CAPTURE_DR_STATE: nstate = tms ? EXIT1_DR_STATE : SHIFT_DR_STATE; SHIFT_DR_STATE: nstate = tms ? EXIT1_DR_STATE : SHIFT_DR_STATE; EXIT1_DR_STATE: nstate = tms ? UPDATE_DR_STATE : PAUSE_DR_STATE; PAUSE_DR_STATE: nstate = tms ? EXIT2_DR_STATE : PAUSE_DR_STATE; EXIT2_DR_STATE: nstate = tms ? UPDATE_DR_STATE : SHIFT_DR_STATE; UPDATE_DR_STATE: nstate = tms ? SELECT_DR_SCAN_STATE : RUN_TEST_IDLE_STATE; SELECT_IR_SCAN_STATE: nstate = tms ? TEST_LOGIC_RESET_STATE : CAPTURE_IR_STATE; CAPTURE_IR_STATE: nstate = tms ? EXIT1_IR_STATE : SHIFT_IR_STATE; SHIFT_IR_STATE: nstate = tms ? EXIT1_IR_STATE : SHIFT_IR_STATE; EXIT1_IR_STATE: nstate = tms ? UPDATE_IR_STATE : PAUSE_IR_STATE; PAUSE_IR_STATE: nstate = tms ? EXIT2_IR_STATE : PAUSE_IR_STATE; EXIT2_IR_STATE: nstate = tms ? UPDATE_IR_STATE : SHIFT_IR_STATE; UPDATE_IR_STATE: nstate = tms ? SELECT_DR_SCAN_STATE : RUN_TEST_IDLE_STATE; default: nstate = TEST_LOGIC_RESET_STATE; endcase end always @ (posedge tck or negedge trst) begin if(!trst) state <= TEST_LOGIC_RESET_STATE; else state <= nstate; end assign jtag_reset = state == TEST_LOGIC_RESET_STATE; assign shift_dr = state == SHIFT_DR_STATE; assign pause_dr = state == PAUSE_DR_STATE; assign update_dr = state == UPDATE_DR_STATE; assign capture_dr = state == CAPTURE_DR_STATE; assign shift_ir = state == SHIFT_IR_STATE; assign pause_ir = state == PAUSE_IR_STATE; assign update_ir = state == UPDATE_IR_STATE; assign capture_ir = state == CAPTURE_IR_STATE; assign tdoEnable = shift_dr | shift_ir; /////////////////////////////////////////////////////// // IR register /////////////////////////////////////////////////////// always @ (negedge tck or negedge trst) begin if (!trst) ir <= 5'b1; else begin if (jtag_reset) ir <= 5'b1; else if (update_ir) ir <= (sr[4:0] == '0) ? 5'h1f :sr[4:0]; end end assign devid_sel = ir == 5'b00001; assign dr_en[0] = ir == 5'b10000; assign dr_en[1] = ir == 5'b10001; /////////////////////////////////////////////////////// // Shift register /////////////////////////////////////////////////////// always @ (posedge tck or negedge trst) begin if(!trst)begin sr <= '0; end else begin sr <= nsr; end end // SR next value always_comb begin nsr = sr; case(1) shift_dr: begin case(1) dr_en[1]: nsr = {tdi, sr[USER_DR_LENGTH-1:1]}; dr_en[0], devid_sel: nsr = {{USER_DR_LENGTH-32{1'b0}},tdi, sr[31:1]}; default: nsr = {{USER_DR_LENGTH-1{1'b0}},tdi}; // bypass endcase end capture_dr: begin nsr[0] = 1'b0; case(1) dr_en[0]: nsr = {{USER_DR_LENGTH-15{1'b0}}, idle, dmi_stat, abits, version}; dr_en[1]: nsr = {{AWIDTH{1'b0}}, rd_data, rd_status}; devid_sel: nsr = {{USER_DR_LENGTH-32{1'b0}}, jtag_id, 1'b1}; endcase end shift_ir: nsr = {{USER_DR_LENGTH-5{1'b0}},tdi, sr[4:1]}; capture_ir: nsr = {{USER_DR_LENGTH-1{1'b0}},1'b1}; endcase end // TDO retiming always @ (negedge tck ) tdo <= sr[0]; // DMI CS register always @ (posedge tck or negedge trst) begin if(!trst) begin dmi_hard_reset <= 1'b0; dmi_reset <= 1'b0; end else if (update_dr & dr_en[0]) begin dmi_hard_reset <= sr[17]; dmi_reset <= sr[16]; end else begin dmi_hard_reset <= 1'b0; dmi_reset <= 1'b0; end end // DR register always @ (posedge tck or negedge trst) begin if(!trst) dr <= '0; else begin if (update_dr & dr_en[1]) dr <= sr; else dr <= {dr[USER_DR_LENGTH-1:2],2'b0}; end end assign {wr_addr, wr_data, wr_en, rd_en} = dr; endmodule ================================================ FILE: design/el2_dma_ctrl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // Function: Top level VeeR core file // Comments: // //******************************************************************************** module el2_dma_ctrl import el2_pkg::*; #( `include "el2_param.vh" )( input logic clk, input logic free_clk, input logic rst_l, input logic dma_bus_clk_en, // slave bus clock enable input logic clk_override, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ // Debug signals input logic [31:0] dbg_cmd_addr, input logic [31:0] dbg_cmd_wrdata, input logic dbg_cmd_valid, input logic dbg_cmd_write, // 1: write command, 0: read_command input logic [1:0] dbg_cmd_type, // 0:gpr 1:csr 2: memory input logic [1:0] dbg_cmd_size, // size of the abstract mem access debug command input logic dbg_dma_bubble, // Debug needs a bubble to send a valid output logic dma_dbg_ready, // DMA is ready to accept debug request output logic dma_dbg_cmd_done, output logic dma_dbg_cmd_fail, output logic [31:0] dma_dbg_rddata, // Core side signals output logic dma_dccm_req, // DMA dccm request (only one of dccm/iccm will be set) output logic dma_iccm_req, // DMA iccm request output logic [2:0] dma_mem_tag, // DMA Buffer entry number output logic [31:0] dma_mem_addr, // DMA request address output logic [2:0] dma_mem_sz, // DMA request size output logic dma_mem_write, // DMA write to dccm/iccm output logic [63:0] dma_mem_wdata, // DMA write data input logic dccm_dma_rvalid, // dccm data valid for DMA read input logic dccm_dma_ecc_error, // ECC error on DMA read input logic [2:0] dccm_dma_rtag, // Tag of the DMA req input logic [63:0] dccm_dma_rdata, // dccm data for DMA read input logic iccm_dma_rvalid, // iccm data valid for DMA read input logic iccm_dma_ecc_error, // ECC error on DMA read input logic [2:0] iccm_dma_rtag, // Tag of the DMA req input logic [63:0] iccm_dma_rdata, // iccm data for DMA read output logic dma_active, // DMA is busy output logic dma_dccm_stall_any, // stall dccm pipe (bubble) so that DMA can proceed output logic dma_iccm_stall_any, // stall iccm pipe (bubble) so that DMA can proceed input logic dccm_ready, // dccm ready to accept DMA request input logic iccm_ready, // iccm ready to accept DMA request input logic [2:0] dec_tlu_dma_qos_prty, // DMA QoS priority coming from MFDC [18:15] // PMU signals output logic dma_pmu_dccm_read, output logic dma_pmu_dccm_write, output logic dma_pmu_any_read, output logic dma_pmu_any_write, // AXI Write Channels input logic dma_axi_awvalid, output logic dma_axi_awready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid, input logic [31:0] dma_axi_awaddr, input logic [2:0] dma_axi_awsize, input logic dma_axi_wvalid, output logic dma_axi_wready, input logic [63:0] dma_axi_wdata, input logic [7:0] dma_axi_wstrb, output logic dma_axi_bvalid, input logic dma_axi_bready, output logic [1:0] dma_axi_bresp, output logic [pt.DMA_BUS_TAG-1:0] dma_axi_bid, // AXI Read Channels input logic dma_axi_arvalid, output logic dma_axi_arready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid, input logic [31:0] dma_axi_araddr, input logic [2:0] dma_axi_arsize, output logic dma_axi_rvalid, input logic dma_axi_rready, output logic [pt.DMA_BUS_TAG-1:0] dma_axi_rid, output logic [63:0] dma_axi_rdata, output logic [1:0] dma_axi_rresp, output logic dma_axi_rlast ); localparam DEPTH = pt.DMA_BUF_DEPTH; localparam DEPTH_PTR = $clog2(DEPTH); localparam NACK_COUNT = 7; logic [DEPTH-1:0] fifo_valid; logic [DEPTH-1:0][1:0] fifo_error; logic [DEPTH-1:0] fifo_error_bus; logic [DEPTH-1:0] fifo_rpend; logic [DEPTH-1:0] fifo_done; // DMA trxn is done in core logic [DEPTH-1:0] fifo_done_bus; // DMA trxn is done in core but synced to bus clock logic [DEPTH-1:0][31:0] fifo_addr; logic [DEPTH-1:0][2:0] fifo_sz; logic [DEPTH-1:0][7:0] fifo_byteen; logic [DEPTH-1:0] fifo_write; logic [DEPTH-1:0] fifo_posted_write; logic [DEPTH-1:0] fifo_dbg; logic [DEPTH-1:0][63:0] fifo_data; logic [DEPTH-1:0][pt.DMA_BUS_TAG-1:0] fifo_tag; logic [DEPTH-1:0][pt.DMA_BUS_ID-1:0] fifo_mid; logic [DEPTH-1:0][pt.DMA_BUS_PRTY-1:0] fifo_prty; logic [DEPTH-1:0] fifo_cmd_en; logic [DEPTH-1:0] fifo_data_en; logic [DEPTH-1:0] fifo_pend_en; logic [DEPTH-1:0] fifo_done_en; logic [DEPTH-1:0] fifo_done_bus_en; logic [DEPTH-1:0] fifo_error_en; logic [DEPTH-1:0] fifo_error_bus_en; logic [DEPTH-1:0] fifo_reset; logic [DEPTH-1:0][1:0] fifo_error_in; logic [DEPTH-1:0][63:0] fifo_data_in; logic fifo_write_in; logic fifo_posted_write_in; logic fifo_dbg_in; logic [31:0] fifo_addr_in; logic [2:0] fifo_sz_in; logic [7:0] fifo_byteen_in; logic [DEPTH_PTR-1:0] RspPtr, NxtRspPtr; logic [DEPTH_PTR-1:0] WrPtr, NxtWrPtr; logic [DEPTH_PTR-1:0] RdPtr, NxtRdPtr; logic WrPtrEn, RdPtrEn, RspPtrEn; logic [1:0] dma_dbg_sz; logic [1:0] dma_dbg_addr; logic [31:0] dma_dbg_mem_rddata; logic [31:0] dma_dbg_mem_wrdata; logic dma_dbg_cmd_error; logic dma_dbg_cmd_done_q; logic fifo_full, fifo_full_spec, fifo_empty; logic dma_address_error, dma_alignment_error; logic [3:0] num_fifo_vld; logic dma_mem_req; logic [31:0] dma_mem_addr_int; logic [2:0] dma_mem_sz_int; logic [7:0] dma_mem_byteen; logic dma_mem_addr_in_dccm; logic dma_mem_addr_in_iccm; logic dma_mem_addr_in_pic; logic dma_mem_addr_in_pic_region_nc; logic dma_mem_addr_in_dccm_region_nc; logic dma_mem_addr_in_iccm_region_nc; logic [2:0] dma_nack_count, dma_nack_count_d, dma_nack_count_csr; logic dma_buffer_c1_clken; logic dma_free_clken; logic dma_buffer_c1_clk; logic dma_free_clk; logic dma_bus_clk; logic bus_rsp_valid, bus_rsp_sent; logic bus_cmd_valid, bus_cmd_sent; logic bus_cmd_write, bus_cmd_posted_write; logic [7:0] bus_cmd_byteen; logic [2:0] bus_cmd_sz; logic [31:0] bus_cmd_addr; logic [63:0] bus_cmd_wdata; logic [pt.DMA_BUS_TAG-1:0] bus_cmd_tag; logic [pt.DMA_BUS_ID-1:0] bus_cmd_mid; logic [pt.DMA_BUS_PRTY-1:0] bus_cmd_prty; logic bus_posted_write_done; logic fifo_full_spec_bus; logic dbg_dma_bubble_bus; logic stall_dma_in; logic dma_fifo_ready; logic wrbuf_en, wrbuf_data_en; logic wrbuf_cmd_sent, wrbuf_rst, wrbuf_data_rst; logic wrbuf_vld, wrbuf_data_vld; logic [pt.DMA_BUS_TAG-1:0] wrbuf_tag; logic [2:0] wrbuf_sz; logic [31:0] wrbuf_addr; logic [63:0] wrbuf_data; logic [7:0] wrbuf_byteen; logic rdbuf_en; logic rdbuf_cmd_sent, rdbuf_rst; logic rdbuf_vld; logic [pt.DMA_BUS_TAG-1:0] rdbuf_tag; logic [2:0] rdbuf_sz; logic [31:0] rdbuf_addr; logic axi_mstr_prty_in, axi_mstr_prty_en; logic axi_mstr_priority; logic axi_mstr_sel; logic axi_rsp_valid; logic axi_rsp_write; logic [pt.DMA_BUS_TAG-1:0] axi_rsp_tag; logic [1:0] axi_rsp_error; logic [63:0] axi_rsp_rdata; //------------------------LOGIC STARTS HERE--------------------------------- // FIFO inputs assign fifo_addr_in[31:0] = dbg_cmd_valid ? dbg_cmd_addr[31:0] : bus_cmd_addr[31:0]; assign fifo_byteen_in[7:0] = {8{~dbg_cmd_valid}} & bus_cmd_byteen[7:0]; // Byte enable is used only for bus requests assign fifo_sz_in[2:0] = dbg_cmd_valid ? {1'b0,dbg_cmd_size[1:0]} : bus_cmd_sz[2:0]; assign fifo_write_in = dbg_cmd_valid ? dbg_cmd_write : bus_cmd_write; assign fifo_posted_write_in = ~dbg_cmd_valid & bus_cmd_posted_write; assign fifo_dbg_in = dbg_cmd_valid; for (genvar i=0 ;i= DEPTH); assign dma_fifo_ready = ~(fifo_full | dbg_dma_bubble_bus); // Error logic assign dma_address_error = fifo_valid[RdPtr] & ~fifo_done[RdPtr] & ~fifo_dbg[RdPtr] & (~(dma_mem_addr_in_dccm | dma_mem_addr_in_iccm)); // request not for ICCM or DCCM assign dma_alignment_error = fifo_valid[RdPtr] & ~fifo_done[RdPtr] & ~fifo_dbg[RdPtr] & ~dma_address_error & (((dma_mem_sz_int[2:0] == 3'h1) & dma_mem_addr_int[0]) | // HW size but unaligned ((dma_mem_sz_int[2:0] == 3'h2) & (|dma_mem_addr_int[1:0])) | // W size but unaligned ((dma_mem_sz_int[2:0] == 3'h3) & (|dma_mem_addr_int[2:0])) | // DW size but unaligned (dma_mem_addr_in_iccm & ~((dma_mem_sz_int[1:0] == 2'b10) | (dma_mem_sz_int[1:0] == 2'b11))) | // ICCM access not word size (dma_mem_addr_in_dccm & dma_mem_write & ~((dma_mem_sz_int[1:0] == 2'b10) | (dma_mem_sz_int[1:0] == 2'b11))) | // DCCM write not word size (dma_mem_write & (dma_mem_sz_int[2:0] == 3'h2) & (dma_mem_addr_int[2:0] == 3'h0) & (dma_mem_byteen[3:0] != 4'hf)) | // Write byte enables not aligned for word store (dma_mem_write & (dma_mem_sz_int[2:0] == 3'h2) & (dma_mem_addr_int[2:0] == 3'h4) & (dma_mem_byteen[7:4] != 4'hf)) | // Write byte enables not aligned for word store (dma_mem_write & (dma_mem_sz_int[2:0] == 3'h3) & ~((dma_mem_byteen[7:0] == 8'h0f) | (dma_mem_byteen[7:0] == 8'hf0) | (dma_mem_byteen[7:0] == 8'hff)))); // Write byte enables not aligned for dword store //Dbg outputs assign dma_dbg_ready = fifo_empty & dbg_dma_bubble; assign dma_dbg_cmd_done = (fifo_valid[RspPtr] & fifo_dbg[RspPtr] & fifo_done[RspPtr]); assign dma_dbg_cmd_fail = (|fifo_error[RspPtr] & dma_dbg_cmd_done) ; assign dma_dbg_sz[1:0] = fifo_sz[RspPtr][1:0]; assign dma_dbg_addr[1:0] = fifo_addr[RspPtr][1:0]; assign dma_dbg_mem_rddata[31:0] = fifo_addr[RspPtr][2] ? fifo_data[RspPtr][63:32] : fifo_data[RspPtr][31:0]; assign dma_dbg_rddata[31:0] = ({32{(dma_dbg_sz[1:0] == 2'h0)}} & ((dma_dbg_mem_rddata[31:0] >> 8*dma_dbg_addr[1:0]) & 32'hff)) | ({32{(dma_dbg_sz[1:0] == 2'h1)}} & ((dma_dbg_mem_rddata[31:0] >> 16*dma_dbg_addr[1]) & 32'hffff)) | ({32{(dma_dbg_sz[1:0] == 2'h2)}} & dma_dbg_mem_rddata[31:0]); assign dma_dbg_cmd_error = fifo_valid[RdPtr] & ~fifo_done[RdPtr] & fifo_dbg[RdPtr] & ((~(dma_mem_addr_in_dccm | dma_mem_addr_in_iccm | dma_mem_addr_in_pic)) | // Address outside of ICCM/DCCM/PIC ((dma_mem_addr_in_iccm | dma_mem_addr_in_pic) & (dma_mem_sz_int[1:0] != 2'b10))); // Only word accesses allowed for ICCM/PIC assign dma_dbg_mem_wrdata[31:0] = ({32{dbg_cmd_size[1:0] == 2'h0}} & {4{dbg_cmd_wrdata[7:0]}}) | ({32{dbg_cmd_size[1:0] == 2'h1}} & {2{dbg_cmd_wrdata[15:0]}}) | ({32{dbg_cmd_size[1:0] == 2'h2}} & dbg_cmd_wrdata[31:0]); // Block the decode if fifo full assign dma_dccm_stall_any = dma_mem_req & (dma_mem_addr_in_dccm | dma_mem_addr_in_pic) & (dma_nack_count >= dma_nack_count_csr); assign dma_iccm_stall_any = dma_mem_req & dma_mem_addr_in_iccm & (dma_nack_count >= dma_nack_count_csr); // Used to indicate ready to debug assign fifo_empty = ~((|(fifo_valid[DEPTH-1:0])) | bus_cmd_sent); // Nack counter, stall the lsu pipe if 7 nacks assign dma_nack_count_csr[2:0] = dec_tlu_dma_qos_prty[2:0]; assign dma_nack_count_d[2:0] = (dma_nack_count[2:0] >= dma_nack_count_csr[2:0]) ? ({3{~(dma_dccm_req | dma_iccm_req)}} & dma_nack_count[2:0]) : (dma_mem_req & ~(dma_dccm_req | dma_iccm_req)) ? (dma_nack_count[2:0] + 1'b1) : 3'b0; rvdffs #(3) nack_count_dff(.din(dma_nack_count_d[2:0]), .dout(dma_nack_count[2:0]), .en(dma_mem_req), .clk(dma_free_clk), .*); // Core outputs assign dma_mem_req = fifo_valid[RdPtr] & ~fifo_rpend[RdPtr] & ~fifo_done[RdPtr] & ~(dma_address_error | dma_alignment_error | dma_dbg_cmd_error); assign dma_dccm_req = dma_mem_req & (dma_mem_addr_in_dccm | dma_mem_addr_in_pic) & dccm_ready; assign dma_iccm_req = dma_mem_req & dma_mem_addr_in_iccm & iccm_ready; assign dma_mem_tag[2:0] = 3'(RdPtr); assign dma_mem_addr_int[31:0] = fifo_addr[RdPtr]; assign dma_mem_sz_int[2:0] = fifo_sz[RdPtr]; assign dma_mem_addr[31:0] = (dma_mem_write & ~fifo_dbg[RdPtr] & (dma_mem_byteen[7:0] == 8'hf0)) ? {dma_mem_addr_int[31:3],1'b1,dma_mem_addr_int[1:0]} : dma_mem_addr_int[31:0]; assign dma_mem_sz[2:0] = (dma_mem_write & ~fifo_dbg[RdPtr] & ((dma_mem_byteen[7:0] == 8'h0f) | (dma_mem_byteen[7:0] == 8'hf0))) ? 3'h2 : dma_mem_sz_int[2:0]; assign dma_mem_byteen[7:0] = fifo_byteen[RdPtr]; assign dma_mem_write = fifo_write[RdPtr]; assign dma_mem_wdata[63:0] = fifo_data[RdPtr]; // PMU outputs assign dma_pmu_dccm_read = dma_dccm_req & ~dma_mem_write; assign dma_pmu_dccm_write = dma_dccm_req & dma_mem_write; assign dma_pmu_any_read = (dma_dccm_req | dma_iccm_req) & ~dma_mem_write; assign dma_pmu_any_write = (dma_dccm_req | dma_iccm_req) & dma_mem_write; // Address check dccm if (pt.DCCM_ENABLE) begin: Gen_dccm_enable rvrangecheck #(.CCM_SADR(pt.DCCM_SADR), .CCM_SIZE(pt.DCCM_SIZE)) addr_dccm_rangecheck ( .addr(dma_mem_addr_int[31:0]), .in_range(dma_mem_addr_in_dccm), .in_region(dma_mem_addr_in_dccm_region_nc) ); end else begin: Gen_dccm_disable assign dma_mem_addr_in_dccm = '0; assign dma_mem_addr_in_dccm_region_nc = '0; end // else: !if(pt.ICCM_ENABLE) // Address check iccm if (pt.ICCM_ENABLE) begin: Gen_iccm_enable rvrangecheck #(.CCM_SADR(pt.ICCM_SADR), .CCM_SIZE(pt.ICCM_SIZE)) addr_iccm_rangecheck ( .addr(dma_mem_addr_int[31:0]), .in_range(dma_mem_addr_in_iccm), .in_region(dma_mem_addr_in_iccm_region_nc) ); end else begin: Gen_iccm_disable assign dma_mem_addr_in_iccm = '0; assign dma_mem_addr_in_iccm_region_nc = '0; end // else: !if(pt.ICCM_ENABLE) // PIC memory address check rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR), .CCM_SIZE(pt.PIC_SIZE)) addr_pic_rangecheck ( .addr(dma_mem_addr_int[31:0]), .in_range(dma_mem_addr_in_pic), .in_region(dma_mem_addr_in_pic_region_nc) ); // Inputs rvdff_fpga #(1) fifo_full_bus_ff (.din(fifo_full_spec), .dout(fifo_full_spec_bus), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(1) dbg_dma_bubble_ff (.din(dbg_dma_bubble), .dout(dbg_dma_bubble_bus), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdff #(1) dma_dbg_cmd_doneff (.din(dma_dbg_cmd_done), .dout(dma_dbg_cmd_done_q), .clk(free_clk), .*); // Clock Gating logic assign dma_buffer_c1_clken = (bus_cmd_valid & dma_bus_clk_en) | dbg_cmd_valid | clk_override; assign dma_free_clken = (bus_cmd_valid | bus_rsp_valid | dbg_cmd_valid | dma_dbg_cmd_done | dma_dbg_cmd_done_q | (|fifo_valid[DEPTH-1:0]) | clk_override); rvoclkhdr dma_buffer_c1cgc ( .en(dma_buffer_c1_clken), .l1clk(dma_buffer_c1_clk), .* ); rvoclkhdr dma_free_cgc (.en(dma_free_clken), .l1clk(dma_free_clk), .*); `ifdef RV_FPGA_OPTIMIZE assign dma_bus_clk = 1'b0; `else rvclkhdr dma_bus_cgc (.en(dma_bus_clk_en), .l1clk(dma_bus_clk), .*); `endif // Write channel buffer assign wrbuf_en = dma_axi_awvalid & dma_axi_awready; assign wrbuf_data_en = dma_axi_wvalid & dma_axi_wready; assign wrbuf_cmd_sent = bus_cmd_sent & bus_cmd_write; assign wrbuf_rst = wrbuf_cmd_sent & ~wrbuf_en; assign wrbuf_data_rst = wrbuf_cmd_sent & ~wrbuf_data_en; rvdffsc_fpga #(.WIDTH(1)) wrbuf_vldff (.din(1'b1), .dout(wrbuf_vld), .en(wrbuf_en), .clear(wrbuf_rst), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdffsc_fpga #(.WIDTH(1)) wrbuf_data_vldff (.din(1'b1), .dout(wrbuf_data_vld), .en(wrbuf_data_en), .clear(wrbuf_data_rst), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(pt.DMA_BUS_TAG)) wrbuf_tagff (.din(dma_axi_awid[pt.DMA_BUS_TAG-1:0]), .dout(wrbuf_tag[pt.DMA_BUS_TAG-1:0]), .en(wrbuf_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(3)) wrbuf_szff (.din(dma_axi_awsize[2:0]), .dout(wrbuf_sz[2:0]), .en(wrbuf_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdffe #(.WIDTH(32)) wrbuf_addrff (.din(dma_axi_awaddr[31:0]), .dout(wrbuf_addr[31:0]), .en(wrbuf_en & dma_bus_clk_en), .*); rvdffe #(.WIDTH(64)) wrbuf_dataff (.din(dma_axi_wdata[63:0]), .dout(wrbuf_data[63:0]), .en(wrbuf_data_en & dma_bus_clk_en), .*); rvdffs_fpga #(.WIDTH(8)) wrbuf_byteenff (.din(dma_axi_wstrb[7:0]), .dout(wrbuf_byteen[7:0]), .en(wrbuf_data_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); // Read channel buffer assign rdbuf_en = dma_axi_arvalid & dma_axi_arready; assign rdbuf_cmd_sent = bus_cmd_sent & ~bus_cmd_write; assign rdbuf_rst = rdbuf_cmd_sent & ~rdbuf_en; rvdffsc_fpga #(.WIDTH(1)) rdbuf_vldff (.din(1'b1), .dout(rdbuf_vld), .en(rdbuf_en), .clear(rdbuf_rst), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(pt.DMA_BUS_TAG)) rdbuf_tagff (.din(dma_axi_arid[pt.DMA_BUS_TAG-1:0]), .dout(rdbuf_tag[pt.DMA_BUS_TAG-1:0]), .en(rdbuf_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(3)) rdbuf_szff (.din(dma_axi_arsize[2:0]), .dout(rdbuf_sz[2:0]), .en(rdbuf_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); rvdffe #(.WIDTH(32)) rdbuf_addrff (.din(dma_axi_araddr[31:0]), .dout(rdbuf_addr[31:0]), .en(rdbuf_en & dma_bus_clk_en), .*); assign dma_axi_awready = ~(wrbuf_vld & ~wrbuf_cmd_sent); assign dma_axi_wready = ~(wrbuf_data_vld & ~wrbuf_cmd_sent); assign dma_axi_arready = ~(rdbuf_vld & ~rdbuf_cmd_sent); //Generate a single request from read/write channel assign bus_cmd_valid = (wrbuf_vld & wrbuf_data_vld) | rdbuf_vld; assign bus_cmd_sent = bus_cmd_valid & dma_fifo_ready; assign bus_cmd_write = axi_mstr_sel; assign bus_cmd_posted_write = '0; assign bus_cmd_addr[31:0] = axi_mstr_sel ? wrbuf_addr[31:0] : rdbuf_addr[31:0]; assign bus_cmd_sz[2:0] = axi_mstr_sel ? wrbuf_sz[2:0] : rdbuf_sz[2:0]; assign bus_cmd_wdata[63:0] = wrbuf_data[63:0]; assign bus_cmd_byteen[7:0] = wrbuf_byteen[7:0]; assign bus_cmd_tag[pt.DMA_BUS_TAG-1:0] = axi_mstr_sel ? wrbuf_tag[pt.DMA_BUS_TAG-1:0] : rdbuf_tag[pt.DMA_BUS_TAG-1:0]; assign bus_cmd_mid[pt.DMA_BUS_ID-1:0] = '0; assign bus_cmd_prty[pt.DMA_BUS_PRTY-1:0] = '0; // Sel=1 -> write has higher priority assign axi_mstr_sel = (wrbuf_vld & wrbuf_data_vld & rdbuf_vld) ? axi_mstr_priority : (wrbuf_vld & wrbuf_data_vld); assign axi_mstr_prty_in = ~axi_mstr_priority; assign axi_mstr_prty_en = bus_cmd_sent; rvdffs_fpga #(.WIDTH(1)) mstr_prtyff(.din(axi_mstr_prty_in), .dout(axi_mstr_priority), .en(axi_mstr_prty_en), .clk(dma_bus_clk), .clken(dma_bus_clk_en), .rawclk(clk), .*); assign axi_rsp_valid = fifo_valid[RspPtr] & ~fifo_dbg[RspPtr] & fifo_done_bus[RspPtr]; assign axi_rsp_rdata[63:0] = fifo_data[RspPtr]; assign axi_rsp_write = fifo_write[RspPtr]; assign axi_rsp_error[1:0] = fifo_error[RspPtr][0] ? 2'b10 : (fifo_error[RspPtr][1] ? 2'b11 : 2'b0); assign axi_rsp_tag[pt.DMA_BUS_TAG-1:0] = fifo_tag[RspPtr]; // AXI response channel signals assign dma_axi_bvalid = axi_rsp_valid & axi_rsp_write; assign dma_axi_bresp[1:0] = axi_rsp_error[1:0]; assign dma_axi_bid[pt.DMA_BUS_TAG-1:0] = axi_rsp_tag[pt.DMA_BUS_TAG-1:0]; assign dma_axi_rvalid = axi_rsp_valid & ~axi_rsp_write; assign dma_axi_rresp[1:0] = axi_rsp_error; assign dma_axi_rdata[63:0] = axi_rsp_rdata[63:0]; assign dma_axi_rlast = 1'b1; assign dma_axi_rid[pt.DMA_BUS_TAG-1:0] = axi_rsp_tag[pt.DMA_BUS_TAG-1:0]; assign bus_posted_write_done = 1'b0; assign bus_rsp_valid = (dma_axi_bvalid | dma_axi_rvalid); assign bus_rsp_sent = (dma_axi_bvalid & dma_axi_bready) | (dma_axi_rvalid & dma_axi_rready); assign dma_active = wrbuf_vld | rdbuf_vld | (|fifo_valid[DEPTH-1:0]); `ifdef RV_ASSERT_ON for (genvar i=0; i $past(dma_bus_clk_en); endproperty assert_dma_axi_awvalid_stable: assert property (dma_axi_awvalid_stable) else $display("DMA AXI awvalid changed in middle of bus clock"); // Assertion to check awid stays stable during entire bus clock property dma_axi_awid_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_awvalid & (dma_axi_awid[pt.DMA_BUS_TAG-1:0] != $past(dma_axi_awid[pt.DMA_BUS_TAG-1:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_awid_stable: assert property (dma_axi_awid_stable) else $display("DMA AXI awid changed in middle of bus clock"); // Assertion to check awaddr stays stable during entire bus clock property dma_axi_awaddr_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_awvalid & (dma_axi_awaddr[31:0] != $past(dma_axi_awaddr[31:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_awaddr_stable: assert property (dma_axi_awaddr_stable) else $display("DMA AXI awaddr changed in middle of bus clock"); // Assertion to check awsize stays stable during entire bus clock property dma_axi_awsize_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_awvalid & (dma_axi_awsize[2:0] != $past(dma_axi_awsize[2:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_awsize_stable: assert property (dma_axi_awsize_stable) else $display("DMA AXI awsize changed in middle of bus clock"); // Assertion to check wstrb stays stable during entire bus clock property dma_axi_wstrb_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_wvalid & (dma_axi_wstrb[7:0] != $past(dma_axi_wstrb[7:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_wstrb_stable: assert property (dma_axi_wstrb_stable) else $display("DMA AXI wstrb changed in middle of bus clock"); // Assertion to check wdata stays stable during entire bus clock property dma_axi_wdata_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_wvalid & (dma_axi_wdata[63:0] != $past(dma_axi_wdata[63:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_wdata_stable: assert property (dma_axi_wdata_stable) else $display("DMA AXI wdata changed in middle of bus clock"); // Assertion to check awvalid stays stable during entire bus clock property dma_axi_arvalid_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_arvalid != $past(dma_axi_arvalid)) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_arvalid_stable: assert property (dma_axi_arvalid_stable) else $display("DMA AXI awvalid changed in middle of bus clock"); // Assertion to check awid stays stable during entire bus clock property dma_axi_arid_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_arvalid & (dma_axi_arid[pt.DMA_BUS_TAG-1:0] != $past(dma_axi_arid[pt.DMA_BUS_TAG-1:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_arid_stable: assert property (dma_axi_arid_stable) else $display("DMA AXI awid changed in middle of bus clock"); // Assertion to check awaddr stays stable during entire bus clock property dma_axi_araddr_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_arvalid & (dma_axi_araddr[31:0] != $past(dma_axi_araddr[31:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_araddr_stable: assert property (dma_axi_araddr_stable) else $display("DMA AXI awaddr changed in middle of bus clock"); // Assertion to check awsize stays stable during entire bus clock property dma_axi_arsize_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_awvalid & (dma_axi_arsize[2:0] != $past(dma_axi_arsize[2:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_arsize_stable: assert property (dma_axi_arsize_stable) else $display("DMA AXI awsize changed in middle of bus clock"); // Assertion to check bvalid stays stable during entire bus clock property dma_axi_bvalid_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_bvalid != $past(dma_axi_bvalid)) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_bvalid_stable: assert property (dma_axi_bvalid_stable) else $display("DMA AXI bvalid changed in middle of bus clock"); // Assertion to check bvalid stays stable if bready is low property dma_axi_bvalid_stable_till_bready; @(posedge clk) disable iff(~rst_l) (~dma_axi_bvalid && $past(dma_axi_bvalid)) |-> $past(dma_axi_bready); endproperty assert_dma_axi_bvalid_stable_till_bready: assert property (dma_axi_bvalid_stable_till_bready) else $display("DMA AXI bvalid deasserted without bready"); // Assertion to check bresp stays stable during entire bus clock property dma_axi_bresp_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_bvalid & (dma_axi_bresp[1:0] != $past(dma_axi_bresp[1:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_bresp_stable: assert property (dma_axi_bresp_stable) else $display("DMA AXI bresp changed in middle of bus clock"); // Assertion to check bid stays stable during entire bus clock property dma_axi_bid_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_bvalid & (dma_axi_bid[pt.DMA_BUS_TAG-1:0] != $past(dma_axi_bid[pt.DMA_BUS_TAG-1:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_bid_stable: assert property (dma_axi_bid_stable) else $display("DMA AXI bid changed in middle of bus clock"); // Assertion to check rvalid stays stable during entire bus clock property dma_axi_rvalid_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_rvalid != $past(dma_axi_rvalid)) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_rvalid_stable: assert property (dma_axi_rvalid_stable) else $display("DMA AXI bvalid changed in middle of bus clock"); // Assertion to check rvalid stays stable if bready is low property dma_axi_rvalid_stable_till_ready; @(posedge clk) disable iff(~rst_l) (~dma_axi_rvalid && $past(dma_axi_rvalid)) |-> $past(dma_axi_rready); endproperty assert_dma_axi_rvalid_stable_till_ready: assert property (dma_axi_rvalid_stable_till_ready) else $display("DMA AXI bvalid changed in middle of bus clock"); // Assertion to check rresp stays stable during entire bus clock property dma_axi_rresp_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_rvalid & (dma_axi_rresp[1:0] != $past(dma_axi_rresp[1:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_rresp_stable: assert property (dma_axi_rresp_stable) else $display("DMA AXI bresp changed in middle of bus clock"); // Assertion to check rid stays stable during entire bus clock property dma_axi_rid_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_rvalid & (dma_axi_rid[pt.DMA_BUS_TAG-1:0] != $past(dma_axi_rid[pt.DMA_BUS_TAG-1:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_rid_stable: assert property (dma_axi_rid_stable) else $display("DMA AXI bid changed in middle of bus clock"); // Assertion to check rdata stays stable during entire bus clock property dma_axi_rdata_stable; @(posedge clk) disable iff(~rst_l) (dma_axi_rvalid & (dma_axi_rdata[63:0] != $past(dma_axi_rdata[63:0]))) |-> $past(dma_bus_clk_en); endproperty assert_dma_axi_rdata_stable: assert property (dma_axi_rdata_stable) else $display("DMA AXI bid changed in middle of bus clock"); `endif endmodule // el2_dma_ctrl ================================================ FILE: design/el2_mem.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // Copyright (c) 2023 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** module el2_mem import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic dccm_clk_override, input logic icm_clk_override, input logic dec_tlu_core_ecc_disable, //DCCM ports input logic dccm_wren, input logic dccm_rden, input logic [pt.DCCM_BITS-1:0] dccm_wr_addr_lo, input logic [pt.DCCM_BITS-1:0] dccm_wr_addr_hi, input logic [pt.DCCM_BITS-1:0] dccm_rd_addr_lo, input logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi, output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, //ICCM ports input logic [pt.ICCM_BITS-1:1] iccm_rw_addr, input logic iccm_buf_correct_ecc, // ICCM is doing a single bit error correct cycle input logic iccm_correction_state, // ICCM is doing a single bit error correct cycle input logic iccm_wren, input logic iccm_rden, input logic [2:0] iccm_wr_size, input logic [77:0] iccm_wr_data, output logic [63:0] iccm_rd_data, output logic [77:0] iccm_rd_data_ecc, // Icache and Itag Ports input logic [31:1] ic_rw_addr, input logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid, input logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en, input logic ic_rd_en, input logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache. input logic ic_sel_premux_data, // Premux data sel input logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC input logic [70:0] ic_debug_wr_data, // Debug wr cache. output logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. input logic ic_debug_rd_en, // Icache debug rd input logic ic_debug_wr_en, // Icache debug wr input logic ic_debug_tag_array, // Debug tag array input logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. output logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC output logic [25:0] ictag_debug_rd_data,// Debug icache tag. output logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, // ecc error per bank output logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, // parity error per bank output logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, output logic ic_tag_perr, // Icache Tag parity error el2_mem_if.veer_sram_src mem_export, el2_mem_if.veer_icache_src icache_export, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); logic active_clk; rvoclkhdr active_cg ( .en(1'b1), .l1clk(active_clk), .* ); el2_mem_if mem_export_local (); assign mem_export_local.clk = clk; assign mem_export .clk = clk; assign mem_export .iccm_clken = mem_export_local.iccm_clken; assign mem_export .iccm_wren_bank = mem_export_local.iccm_wren_bank; assign mem_export .iccm_addr_bank = mem_export_local.iccm_addr_bank; assign mem_export .iccm_bank_wr_data = mem_export_local.iccm_bank_wr_data; assign mem_export .iccm_bank_wr_ecc = mem_export_local.iccm_bank_wr_ecc; assign mem_export_local.iccm_bank_dout = mem_export. iccm_bank_dout; assign mem_export_local.iccm_bank_ecc = mem_export. iccm_bank_ecc; assign mem_export .dccm_clken = mem_export_local.dccm_clken; assign mem_export .dccm_wren_bank = mem_export_local.dccm_wren_bank; assign mem_export .dccm_addr_bank = mem_export_local.dccm_addr_bank; assign mem_export .dccm_wr_data_bank = mem_export_local.dccm_wr_data_bank; assign mem_export .dccm_wr_ecc_bank = mem_export_local.dccm_wr_ecc_bank; assign mem_export_local.dccm_bank_dout = mem_export .dccm_bank_dout; assign mem_export_local.dccm_bank_ecc = mem_export .dccm_bank_ecc; // icache data assign icache_export .ic_b_sb_wren = mem_export_local.ic_b_sb_wren; assign icache_export .ic_b_sb_bit_en_vec = mem_export_local.ic_b_sb_bit_en_vec; assign icache_export .ic_sb_wr_data = mem_export_local.ic_sb_wr_data; assign icache_export .ic_rw_addr_bank_q = mem_export_local.ic_rw_addr_bank_q; assign icache_export .ic_bank_way_clken_final = mem_export_local.ic_bank_way_clken_final; assign icache_export .ic_bank_way_clken_final_up = mem_export_local.ic_bank_way_clken_final_up; assign mem_export_local.wb_packeddout_pre = icache_export .wb_packeddout_pre; assign mem_export_local.wb_dout_pre_up = icache_export .wb_dout_pre_up; // icache tag assign icache_export .ic_tag_clken_final = mem_export_local.ic_tag_clken_final; assign icache_export .ic_tag_wren_q = mem_export_local.ic_tag_wren_q; assign icache_export .ic_tag_wren_biten_vec = mem_export_local.ic_tag_wren_biten_vec; assign icache_export .ic_tag_wr_data = mem_export_local.ic_tag_wr_data; assign icache_export .ic_rw_addr_q = mem_export_local.ic_rw_addr_q; assign mem_export_local.ic_tag_data_raw_packed_pre = icache_export .ic_tag_data_raw_packed_pre; assign mem_export_local.ic_tag_data_raw_pre = icache_export .ic_tag_data_raw_pre; // DCCM Instantiation if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable el2_lsu_dccm_mem #(.pt(pt)) dccm ( .clk_override(dccm_clk_override), .dccm_mem_export(mem_export_local.veer_dccm), .* ); end else begin: Gen_dccm_disable assign dccm_rd_data_lo = '0; assign dccm_rd_data_hi = '0; end if ( pt.ICACHE_ENABLE ) begin: icache el2_ifu_ic_mem #(.pt(pt)) icm ( .clk_override(icm_clk_override), .icache_export(mem_export_local.veer_icache_src), .* ); end else begin assign ic_rd_hit[pt.ICACHE_NUM_WAYS-1:0] = '0; assign ic_tag_perr = '0 ; assign ic_rd_data = '0 ; assign ictag_debug_rd_data = '0 ; assign ic_debug_rd_data = '0 ; assign ic_eccerr = '0; assign ic_parerr = '0; end // else: !if( pt.ICACHE_ENABLE ) if (pt.ICCM_ENABLE) begin : iccm el2_ifu_iccm_mem #(.pt(pt)) iccm (.*, .clk_override(icm_clk_override), .iccm_rw_addr(iccm_rw_addr[pt.ICCM_BITS-1:1]), .iccm_rd_data(iccm_rd_data[63:0]), .iccm_mem_export(mem_export_local.veer_iccm) ); end else begin assign iccm_rd_data = '0 ; assign iccm_rd_data_ecc = '0 ; end endmodule ================================================ FILE: design/el2_pic_ctrl.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** //******************************************************************************** // Function: Programmable Interrupt Controller // Comments: //******************************************************************************** module el2_pic_ctrl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Core clock input logic free_clk, // free clock input logic rst_l, // Reset for all flops input logic clk_override, // Clock over-ride for gating input logic io_clk_override, // PIC IO Clock over-ride for gating input logic [pt.PIC_TOTAL_INT_PLUS1-1:0] extintsrc_req, // Interrupt requests input logic [31:0] picm_rdaddr, // Address of the register input logic [31:0] picm_wraddr, // Address of the register input logic [31:0] picm_wr_data, // Data to be written to the register input logic picm_wren, // Write enable to the register input logic picm_rden, // Read enable for the register input logic picm_mken, // Read the Mask for the register input logic [3:0] meicurpl, // Current Priority Level input logic [3:0] meipt, // Current Priority Threshold output logic mexintpend, // External Inerrupt request to the core output logic [7:0] claimid, // Claim Id of the requested interrupt output logic [3:0] pl, // Priority level of the requested interrupt output logic [31:0] picm_rd_data, // Read data of the register output logic mhwakeup, // Wake-up interrupt request // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // scan mode /*pragma coverage on*/ ); localparam NUM_LEVELS = $clog2(pt.PIC_TOTAL_INT_PLUS1); localparam INTPRIORITY_BASE_ADDR = pt.PIC_BASE_ADDR ; localparam INTPEND_BASE_ADDR = pt.PIC_BASE_ADDR + 32'h00001000 ; localparam INTENABLE_BASE_ADDR = pt.PIC_BASE_ADDR + 32'h00002000 ; localparam EXT_INTR_PIC_CONFIG = pt.PIC_BASE_ADDR + 32'h00003000 ; localparam EXT_INTR_GW_CONFIG = pt.PIC_BASE_ADDR + 32'h00004000 ; localparam EXT_INTR_GW_CLEAR = pt.PIC_BASE_ADDR + 32'h00005000 ; localparam INTPEND_SIZE = (pt.PIC_TOTAL_INT_PLUS1 <= 32) ? 32 : (pt.PIC_TOTAL_INT_PLUS1 <= 64) ? 64 : (pt.PIC_TOTAL_INT_PLUS1 <= 128) ? 128 : (pt.PIC_TOTAL_INT_PLUS1 <= 256) ? 256 : (pt.PIC_TOTAL_INT_PLUS1 <= 512) ? 512 : 1024 ; localparam INT_GRPS = INTPEND_SIZE / 32 ; localparam INTPRIORITY_BITS = 4 ; localparam ID_BITS = 8 ; localparam int GW_CONFIG[pt.PIC_TOTAL_INT_PLUS1-1:0] = '{default:0} ; localparam INT_ENABLE_GRPS = (pt.PIC_TOTAL_INT_PLUS1 - 1) / 4 ; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] intenable_clk_enable ; //logic [INT_ENABLE_GRPS:0] intenable_clk_enable_grp ; logic [INT_ENABLE_GRPS:0] gw_clk ; logic addr_intpend_base_match; logic raddr_config_pic_match ; logic raddr_intenable_base_match; logic raddr_intpriority_base_match; logic raddr_config_gw_base_match ; logic waddr_config_pic_match ; logic waddr_intpriority_base_match; logic waddr_intenable_base_match; logic waddr_config_gw_base_match ; logic addr_clear_gw_base_match ; logic mexintpend_in; logic mhwakeup_in ; logic intpend_reg_read ; logic [31:0] picm_rd_data_in, intpend_rd_out; logic intenable_rd_out ; logic [INTPRIORITY_BITS-1:0] intpriority_rd_out; logic [1:0] gw_config_rd_out; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] [INTPRIORITY_BITS-1:0] intpriority_reg; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] [INTPRIORITY_BITS-1:0] intpriority_reg_inv; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] intpriority_reg_we; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] intpriority_reg_re; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] [1:0] gw_config_reg; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] intenable_reg; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] intenable_reg_we; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] intenable_reg_re; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] gw_config_reg_we; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] gw_config_reg_re; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] gw_clear_reg_we; logic [INTPEND_SIZE-1:0] intpend_reg_extended; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] [INTPRIORITY_BITS-1:0] intpend_w_prior_en; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] [ID_BITS-1:0] intpend_id; logic [INTPRIORITY_BITS-1:0] maxint; logic [INTPRIORITY_BITS-1:0] selected_int_priority; logic [INT_GRPS-1:0] [31:0] intpend_rd_part_out ; logic config_reg; logic intpriord; logic config_reg_we ; logic config_reg_re ; logic config_reg_in ; logic intpriority_reg_read ; logic intenable_reg_read ; logic gw_config_reg_read ; logic picm_wren_ff , picm_rden_ff ; logic [31:0] picm_raddr_ff; logic [31:0] picm_waddr_ff; logic [31:0] picm_wr_data_ff; logic [3:0] mask; logic picm_mken_ff; logic [ID_BITS-1:0] claimid_in ; logic [INTPRIORITY_BITS-1:0] pl_in ; logic [INTPRIORITY_BITS-1:0] pl_in_q ; //logic [pt.PIC_TOTAL_INT_PLUS1-1:0] extintsrc_req_sync; logic [pt.PIC_TOTAL_INT_PLUS1-1:0] extintsrc_req_gw; logic picm_bypass_ff; // clkens logic pic_raddr_c1_clken; logic pic_waddr_c1_clken; logic pic_data_c1_clken; logic pic_pri_c1_clken; logic pic_int_c1_clken; logic gw_config_c1_clken; // clocks logic pic_raddr_c1_clk; logic pic_data_c1_clk; logic pic_pri_c1_clk; logic pic_int_c1_clk; logic gw_config_c1_clk; // ---- Clock gating section ------ // c1 clock enables assign pic_raddr_c1_clken = picm_mken | picm_rden | clk_override; assign pic_data_c1_clken = picm_wren | clk_override; assign pic_pri_c1_clken = (waddr_intpriority_base_match & picm_wren_ff) | (raddr_intpriority_base_match & picm_rden_ff) | clk_override; assign pic_int_c1_clken = (waddr_intenable_base_match & picm_wren_ff) | (raddr_intenable_base_match & picm_rden_ff) | clk_override; assign gw_config_c1_clken = (waddr_config_gw_base_match & picm_wren_ff) | (raddr_config_gw_base_match & picm_rden_ff) | clk_override; // C1 - 1 clock pulse for data rvoclkhdr pic_addr_c1_cgc ( .en(pic_raddr_c1_clken), .l1clk(pic_raddr_c1_clk), .* ); rvoclkhdr pic_data_c1_cgc ( .en(pic_data_c1_clken), .l1clk(pic_data_c1_clk), .* ); rvoclkhdr pic_pri_c1_cgc ( .en(pic_pri_c1_clken), .l1clk(pic_pri_c1_clk), .* ); rvoclkhdr pic_int_c1_cgc ( .en(pic_int_c1_clken), .l1clk(pic_int_c1_clk), .* ); rvoclkhdr gw_config_c1_cgc ( .en(gw_config_c1_clken), .l1clk(gw_config_c1_clk), .* ); // ------ end clock gating section ------------------------ assign raddr_intenable_base_match = (picm_raddr_ff[31:NUM_LEVELS+2] == INTENABLE_BASE_ADDR[31:NUM_LEVELS+2]) ; assign raddr_intpriority_base_match = (picm_raddr_ff[31:NUM_LEVELS+2] == INTPRIORITY_BASE_ADDR[31:NUM_LEVELS+2]) ; assign raddr_config_gw_base_match = (picm_raddr_ff[31:NUM_LEVELS+2] == EXT_INTR_GW_CONFIG[31:NUM_LEVELS+2]) ; assign raddr_config_pic_match = (picm_raddr_ff[31:0] == EXT_INTR_PIC_CONFIG[31:0]) ; assign addr_intpend_base_match = (picm_raddr_ff[31:6] == INTPEND_BASE_ADDR[31:6]) ; assign waddr_config_pic_match = (picm_waddr_ff[31:0] == EXT_INTR_PIC_CONFIG[31:0]) ; assign addr_clear_gw_base_match = (picm_waddr_ff[31:NUM_LEVELS+2] == EXT_INTR_GW_CLEAR[31:NUM_LEVELS+2]) ; assign waddr_intpriority_base_match = (picm_waddr_ff[31:NUM_LEVELS+2] == INTPRIORITY_BASE_ADDR[31:NUM_LEVELS+2]) ; assign waddr_intenable_base_match = (picm_waddr_ff[31:NUM_LEVELS+2] == INTENABLE_BASE_ADDR[31:NUM_LEVELS+2]) ; assign waddr_config_gw_base_match = (picm_waddr_ff[31:NUM_LEVELS+2] == EXT_INTR_GW_CONFIG[31:NUM_LEVELS+2]) ; assign picm_bypass_ff = picm_rden_ff & picm_wren_ff & ( picm_raddr_ff[31:0] == picm_waddr_ff[31:0] ); // pic writes and reads to same address together rvdff #(32) picm_radd_flop (.*, .din (picm_rdaddr), .dout(picm_raddr_ff), .clk(pic_raddr_c1_clk)); rvdff #(32) picm_wadd_flop (.*, .din (picm_wraddr), .dout(picm_waddr_ff), .clk(pic_data_c1_clk)); rvdff #(1) picm_wre_flop (.*, .din (picm_wren), .dout(picm_wren_ff), .clk(free_clk)); rvdff #(1) picm_rde_flop (.*, .din (picm_rden), .dout(picm_rden_ff), .clk(free_clk)); rvdff #(1) picm_mke_flop (.*, .din (picm_mken), .dout(picm_mken_ff), .clk(free_clk)); rvdff #(32) picm_dat_flop (.*, .din (picm_wr_data[31:0]), .dout(picm_wr_data_ff[31:0]), .clk(pic_data_c1_clk)); //rvsyncss #(pt.PIC_TOTAL_INT_PLUS1-1) sync_inst //( // .clk (free_clk), // .dout(extintsrc_req_sync[pt.PIC_TOTAL_INT_PLUS1-1:1]), // .din (extintsrc_req[pt.PIC_TOTAL_INT_PLUS1-1:1]), // .*) ; // //assign extintsrc_req_sync[0] = extintsrc_req[0]; /* genvar p ; for (p=0; p<=INT_ENABLE_GRPS ; p++) begin : IO_CLK_GRP if (p==INT_ENABLE_GRPS) begin : LAST_GRP assign intenable_clk_enable_grp[p] = |intenable_clk_enable[pt.PIC_TOTAL_INT_PLUS1-1 : p*4] | io_clk_override; rvoclkhdr intenable_c1_cgc ( .en(intenable_clk_enable_grp[p]), .l1clk(gw_clk[p]), .* ); end else begin : CLK_GRPS assign intenable_clk_enable_grp[p] = |intenable_clk_enable[p*4+3 : p*4] | io_clk_override; rvoclkhdr intenable_c1_cgc ( .en(intenable_clk_enable_grp[p]), .l1clk(gw_clk[p]), .* ); end end */ genvar i ; genvar p ; for (p=0; p<=INT_ENABLE_GRPS ; p++) begin : IO_CLK_GRP wire grp_clk, grp_clken; assign grp_clken = |intenable_clk_enable[(p==INT_ENABLE_GRPS?pt.PIC_TOTAL_INT_PLUS1-1:p*4+3) : p*4] | io_clk_override; `ifndef RV_FPGA_OPTIMIZE rvclkhdr intenable_c1_cgc( .en(grp_clken), .l1clk(grp_clk), .* ); `else /*pragma coverage off*/ assign gw_clk[p] = 1'b0 ; /*pragma coverage on*/ `endif for(genvar i= (p==0 ? 1: 0); i< (p==INT_ENABLE_GRPS ? pt.PIC_TOTAL_INT_PLUS1-p*4 :4); i++) begin : GW el2_configurable_gw gw_inst( .*, .gw_clk(grp_clk), .rawclk(clk), .clken (grp_clken), .extintsrc_req(extintsrc_req[i+p*4]) , .meigwctrl_polarity(gw_config_reg[i+p*4][0]) , .meigwctrl_type(gw_config_reg[i+p*4][1]) , .meigwclr(gw_clear_reg_we[i+p*4]) , .extintsrc_req_config(extintsrc_req_gw[i+p*4]) ); end end for (i=0; i 0 ) begin : NON_ZERO_INT assign intpriority_reg_we[i] = waddr_intpriority_base_match & (picm_waddr_ff[NUM_LEVELS+1:2] == i) & picm_wren_ff; assign intpriority_reg_re[i] = raddr_intpriority_base_match & (picm_raddr_ff[NUM_LEVELS+1:2] == i) & picm_rden_ff; assign intenable_reg_we[i] = waddr_intenable_base_match & (picm_waddr_ff[NUM_LEVELS+1:2] == i) & picm_wren_ff; assign intenable_reg_re[i] = raddr_intenable_base_match & (picm_raddr_ff[NUM_LEVELS+1:2] == i) & picm_rden_ff; assign gw_config_reg_we[i] = waddr_config_gw_base_match & (picm_waddr_ff[NUM_LEVELS+1:2] == i) & picm_wren_ff; assign gw_config_reg_re[i] = raddr_config_gw_base_match & (picm_raddr_ff[NUM_LEVELS+1:2] == i) & picm_rden_ff; assign gw_clear_reg_we[i] = addr_clear_gw_base_match & (picm_waddr_ff[NUM_LEVELS+1:2] == i) & picm_wren_ff ; rvdffs #(INTPRIORITY_BITS) intpriority_ff (.*, .en( intpriority_reg_we[i]), .din (picm_wr_data_ff[INTPRIORITY_BITS-1:0]), .dout(intpriority_reg[i]), .clk(pic_pri_c1_clk)); rvdffs #(1) intenable_ff (.*, .en( intenable_reg_we[i]), .din (picm_wr_data_ff[0]), .dout(intenable_reg[i]), .clk(pic_int_c1_clk)); rvdffs #(2) gw_config_ff (.*, .en( gw_config_reg_we[i]), .din (picm_wr_data_ff[1:0]), .dout(gw_config_reg[i]), .clk(gw_config_c1_clk)); assign intenable_clk_enable[i] = gw_config_reg[i][1] | intenable_reg_we[i] | intenable_reg[i] | gw_clear_reg_we[i] ; /* rvsyncss_fpga #(1) sync_inst ( .gw_clk (gw_clk[i/4]), .rawclk (clk), .clken (intenable_clk_enable_grp[i/4]), .dout (extintsrc_req_sync[i]), .din (extintsrc_req[i]), .*) ; el2_configurable_gw config_gw_inst(.*, .gw_clk(gw_clk[i/4]), .rawclk(clk), .clken (intenable_clk_enable_grp[i/4]), .extintsrc_req_sync(extintsrc_req_sync[i]) , .meigwctrl_polarity(gw_config_reg[i][0]) , .meigwctrl_type(gw_config_reg[i][1]) , .meigwclr(gw_clear_reg_we[i]) , .extintsrc_req_config(extintsrc_req_gw[i]) ); */ end else begin : INT_ZERO assign intpriority_reg_we[i] = 1'b0 ; assign intpriority_reg_re[i] = 1'b0 ; assign intenable_reg_we[i] = 1'b0 ; assign intenable_reg_re[i] = 1'b0 ; assign gw_config_reg_we[i] = 1'b0 ; assign gw_config_reg_re[i] = 1'b0 ; assign gw_clear_reg_we[i] = 1'b0 ; assign gw_config_reg[i] = '0 ; assign intpriority_reg[i] = {INTPRIORITY_BITS{1'b0}} ; assign intenable_reg[i] = 1'b0 ; assign extintsrc_req_gw[i] = 1'b0 ; // assign extintsrc_req_sync[i] = 1'b0 ; assign intenable_clk_enable[i] = 1'b0; end assign intpriority_reg_inv[i] = intpriord ? ~intpriority_reg[i] : intpriority_reg[i] ; assign intpend_w_prior_en[i] = {INTPRIORITY_BITS{(extintsrc_req_gw[i] & intenable_reg[i])}} & intpriority_reg_inv[i] ; assign intpend_id[i] = i ; end assign pl_in[INTPRIORITY_BITS-1:0] = selected_int_priority[INTPRIORITY_BITS-1:0] ; //if (pt.PIC_2CYCLE == 1) begin : genblock //end //else begin : genblock //end genvar l, m , j, k; if (pt.PIC_2CYCLE == 1) begin : genblock logic [NUM_LEVELS/2:0] [pt.PIC_TOTAL_INT_PLUS1+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en; logic [NUM_LEVELS/2:0] [pt.PIC_TOTAL_INT_PLUS1+2:0] [ID_BITS-1:0] level_intpend_id; logic [NUM_LEVELS:NUM_LEVELS/2] [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] [INTPRIORITY_BITS-1:0] levelx_intpend_w_prior_en; logic [NUM_LEVELS:NUM_LEVELS/2] [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] [ID_BITS-1:0] levelx_intpend_id; assign level_intpend_w_prior_en[0][pt.PIC_TOTAL_INT_PLUS1+2:0] = {4'b0,4'b0,4'b0,intpend_w_prior_en[pt.PIC_TOTAL_INT_PLUS1-1:0]} ; assign level_intpend_id[0][pt.PIC_TOTAL_INT_PLUS1+2:0] = {8'b0,8'b0,8'b0,intpend_id[pt.PIC_TOTAL_INT_PLUS1-1:0]} ; logic [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0] [INTPRIORITY_BITS-1:0] l2_intpend_w_prior_en_ff; logic [(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0] [ID_BITS-1:0] l2_intpend_id_ff; assign levelx_intpend_w_prior_en[NUM_LEVELS/2][(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] = {{1*INTPRIORITY_BITS{1'b0}},l2_intpend_w_prior_en_ff[(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0]} ; assign levelx_intpend_id[NUM_LEVELS/2][(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2))+1:0] = {{1*ID_BITS{1'b1}},l2_intpend_id_ff[(pt.PIC_TOTAL_INT_PLUS1/2**(NUM_LEVELS/2)):0]} ; /// Do the prioritization of the interrupts here //////////// for (l=0; l meipt_inv[INTPRIORITY_BITS-1:0]) & ( selected_int_priority[INTPRIORITY_BITS-1:0] > meicurpl_inv[INTPRIORITY_BITS-1:0]) ); rvdff #(1) mexintpend_ff (.*, .clk(free_clk), .din (mexintpend_in), .dout(mexintpend)); assign maxint[INTPRIORITY_BITS-1:0] = intpriord ? 0 : 15 ; assign mhwakeup_in = ( pl_in_q[INTPRIORITY_BITS-1:0] == maxint) ; rvdff #(1) wake_up_ff (.*, .clk(free_clk), .din (mhwakeup_in), .dout(mhwakeup)); ////////////////////////////////////////////////////////////////////////// // Reads of register. // 1- intpending ////////////////////////////////////////////////////////////////////////// assign intpend_reg_read = addr_intpend_base_match & picm_rden_ff ; assign intpriority_reg_read = raddr_intpriority_base_match & picm_rden_ff; assign intenable_reg_read = raddr_intenable_base_match & picm_rden_ff; assign gw_config_reg_read = raddr_config_gw_base_match & picm_rden_ff; assign intpend_reg_extended[INTPEND_SIZE-1:0] = {{INTPEND_SIZE-pt.PIC_TOTAL_INT_PLUS1{1'b0}},extintsrc_req_gw[pt.PIC_TOTAL_INT_PLUS1-1:0]} ; for (i=0; i<(INT_GRPS); i++) begin assign intpend_rd_part_out[i] = (({32{intpend_reg_read & picm_raddr_ff[5:2] == i}}) & intpend_reg_extended[((32*i)+31):(32*i)]) ; end always_comb begin : INTPEND_RD intpend_rd_out = '0 ; for (int i=0; i // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_pmp import el2_pkg::*; #( parameter PMP_CHANNELS = 3, // Granularity of NAPOT access, // 0 = No restriction, 1 = 8 byte, 2 = 16 byte, 3 = 32 byte, etc. parameter PMP_GRANULARITY = 0, // TODO: Move to veer.config `include "el2_param.vh" ) ( input logic clk, // Top level clock input logic rst_l, // Reset /* pragma coverage off */ input logic scan_mode, // Scan mode /* pragma coverage on */ `ifdef RV_SMEPMP input el2_mseccfg_pkt_t mseccfg, // mseccfg CSR content, RLB, MMWP and MML bits `endif `ifdef RV_USER_MODE input logic priv_mode_ns, // operating privilege mode (next clock cycle) input logic priv_mode_eff, // operating effective privilege mode `endif input el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES], input logic [31:0] pmp_pmpaddr[pt.PMP_ENTRIES], input logic [31:0] pmp_chan_addr[PMP_CHANNELS], input el2_pmp_type_pkt_t pmp_chan_type[PMP_CHANNELS], output logic pmp_chan_err [PMP_CHANNELS] ); logic [ 33:0] csr_pmp_addr_i [pt.PMP_ENTRIES]; logic [ 33:0] pmp_req_addr_i [ PMP_CHANNELS]; logic [ 33:0] region_start_addr [pt.PMP_ENTRIES]; logic [33:PMP_GRANULARITY+2] region_addr_mask [pt.PMP_ENTRIES]; logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_gt; logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_lt; logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_eq; logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_match_all; logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_basic_perm_check; logic [ PMP_CHANNELS-1:0][pt.PMP_ENTRIES-1:0] region_perm_check; `ifdef RV_USER_MODE logic any_region_enabled; `endif /////////////////////// // Functions for PMP // /////////////////////// // Flow of the PMP checking operation follows as below // // basic_perm_check ---> perm_check_wrapper ---> orig_perm_check ---/ // | // region_match_all -----------------> access_fault_check <---------- // | // \--> pmp_chan_err // A wrapper function in which it is decided which form of permission check function gets called function automatic logic perm_check_wrapper(el2_mseccfg_pkt_t csr_pmp_mseccfg, el2_pmp_cfg_pkt_t csr_pmp_cfg, el2_pmp_type_pkt_t req_type, logic priv_mode, logic permission_check); return csr_pmp_mseccfg.MML ? mml_perm_check(csr_pmp_cfg, req_type, priv_mode, permission_check) : orig_perm_check(csr_pmp_cfg.lock, priv_mode, permission_check); endfunction // Compute permissions checks that apply when MSECCFG.MML is set. Added for Smepmp support. function automatic logic mml_perm_check(el2_pmp_cfg_pkt_t csr_pmp_cfg, el2_pmp_type_pkt_t pmp_req_type, logic priv_mode, logic permission_check); logic result; logic unused_cfg = |csr_pmp_cfg.mode; if (!csr_pmp_cfg.read && csr_pmp_cfg.write) begin // Special-case shared regions where R = 0, W = 1 unique case ({csr_pmp_cfg.lock, csr_pmp_cfg.execute}) // Read/write in M, read only in U 2'b00: result = (pmp_req_type == READ) | ((pmp_req_type == WRITE) & ~priv_mode); // Read/write in M/U 2'b01: result = (pmp_req_type == READ) | (pmp_req_type == WRITE); // Execute only on M/U 2'b10: result = (pmp_req_type == EXEC); // Read/execute in M, execute only on U 2'b11: result = (pmp_req_type == EXEC) | ((pmp_req_type == READ) & ~priv_mode); /* pragma coverage off */ default: ; /* pragma coverage on */ endcase end else begin if (csr_pmp_cfg.read & csr_pmp_cfg.write & csr_pmp_cfg.execute & csr_pmp_cfg.lock) begin // Special-case shared read only region when R = 1, W = 1, X = 1, L = 1 result = (pmp_req_type == READ); end else begin // Otherwise use basic permission check. Permission is always denied if in U mode and // L is set or if in M mode and L is unset. result = permission_check & (priv_mode ? ~csr_pmp_cfg.lock : csr_pmp_cfg.lock); end end return result; endfunction // Compute permissions checks that apply when MSECCFG.MML is unset. This is the original PMP // behaviour before Smepmp was added. function automatic logic orig_perm_check(logic pmp_cfg_lock, logic priv_mode, logic permission_check); // For M-mode, any region which matches with the L-bit clear, or with sufficient // access permissions will be allowed. // For other modes, the lock bit doesn't matter return priv_mode ? (permission_check) : (~pmp_cfg_lock | permission_check); endfunction // Access fault determination / prioritization function automatic logic access_fault_check(el2_mseccfg_pkt_t csr_pmp_mseccfg, el2_pmp_type_pkt_t req_type, logic [pt.PMP_ENTRIES-1:0] match_all, logic any_region_enabled, logic priv_mode, logic [pt.PMP_ENTRIES-1:0] final_perm_check); `ifdef RV_USER_MODE `ifdef RV_SMEPMP // When MSECCFG.MMWP is set default deny always, otherwise allow for M-mode, deny for other // modes. Also deny unmatched for M-mode when MSECCFG.MML is set and request type is EXEC. logic access_fail = csr_pmp_mseccfg.MMWP | priv_mode | (csr_pmp_mseccfg.MML && (req_type == EXEC)); `else // When in user mode and at least one PMP region is enabled deny access by default. logic access_fail = any_region_enabled & priv_mode; `endif `else logic access_fail = 1'b0; `endif logic matched = 1'b0; // PMP entries are statically prioritized, from 0 to N-1 // The lowest-numbered PMP entry which matches an address determines accessibility for (int r = 0; r < pt.PMP_ENTRIES; r++) begin if (!matched && match_all[r]) begin access_fail = ~final_perm_check[r]; matched = 1'b1; end end return access_fail; endfunction // --------------- // Access checking // --------------- `ifdef RV_USER_MODE logic [pt.PMP_ENTRIES-1:0] region_enabled; for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_reg_ena assign region_enabled[r] = pmp_pmpcfg[r].mode != OFF; end assign any_region_enabled = |region_enabled; `endif for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_addr_exp assign csr_pmp_addr_i[r] = { pmp_pmpaddr[r], 2'b00 }; // addr conv.: word @ 32-bit -> byte @ 34-bit // Start address for TOR matching if (r == 0) begin : g_entry0 assign region_start_addr[r] = (pmp_pmpcfg[r].mode == TOR) ? 34'h000000000 : csr_pmp_addr_i[r]; end else begin : g_oth assign region_start_addr[r] = (pmp_pmpcfg[r].mode == TOR) ? csr_pmp_addr_i[r-1] : csr_pmp_addr_i[r]; end // Address mask for NA matching for (genvar b = PMP_GRANULARITY + 2; b < 34; b++) begin : g_bitmask if (b == 2) begin : g_bit0 // Always mask bit 2 for NAPOT assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT); end else begin : g_others // We will mask this bit if it is within the programmed granule // i.e. addr = yyyy 0111 // ^ // | This bit pos is the top of the mask, all lower bits set // thus mask = 1111 0000 if (PMP_GRANULARITY == 0) begin : g_region_addr_mask_zero_granularity assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT) | ~&csr_pmp_addr_i[r][b-1:2]; end else begin : g_region_addr_mask_other_granularity assign region_addr_mask[r][b] = (pmp_pmpcfg[r].mode != NAPOT) | ~&csr_pmp_addr_i[r][b-1:PMP_GRANULARITY+1]; end end end end `ifdef RV_USER_MODE logic [PMP_CHANNELS-1:0] pmp_priv_mode_eff; for (genvar c = 0; c < PMP_CHANNELS; c++) begin : g_priv_mode_eff assign pmp_priv_mode_eff[c] = ( ((pmp_chan_type[c] == EXEC) & priv_mode_ns) | ((pmp_chan_type[c] != EXEC) & priv_mode_eff)); // RW affected by mstatus.MPRV end `endif for (genvar c = 0; c < PMP_CHANNELS; c++) begin : g_access_check assign pmp_req_addr_i[c] = {2'b00, pmp_chan_addr[c]}; // addr. widening: 32-bit -> 34-bit for (genvar r = 0; r < pt.PMP_ENTRIES; r++) begin : g_regions // Comparators are sized according to granularity assign region_match_eq[c][r] = (pmp_req_addr_i[c][33:PMP_GRANULARITY+2] & region_addr_mask[r]) == (region_start_addr[r][33:PMP_GRANULARITY+2] & region_addr_mask[r]); assign region_match_gt[c][r] = pmp_req_addr_i[c][33:PMP_GRANULARITY+2] > region_start_addr[r][33:PMP_GRANULARITY+2]; assign region_match_lt[c][r] = pmp_req_addr_i[c][33:PMP_GRANULARITY+2] < csr_pmp_addr_i[r][33:PMP_GRANULARITY+2]; always_comb begin region_match_all[c][r] = 1'b0; unique case (pmp_pmpcfg[r].mode) OFF: region_match_all[c][r] = 1'b0; NA4: region_match_all[c][r] = region_match_eq[c][r]; NAPOT: region_match_all[c][r] = region_match_eq[c][r]; TOR: begin region_match_all[c][r] = (region_match_eq[c][r] | region_match_gt[c][r]) & region_match_lt[c][r]; end default: region_match_all[c][r] = 1'b0; endcase end // Basic permission check compares cfg register only. assign region_basic_perm_check[c][r] = ((pmp_chan_type[c] == EXEC) & pmp_pmpcfg[r].execute) | ((pmp_chan_type[c] == WRITE) & pmp_pmpcfg[r].write) | ((pmp_chan_type[c] == READ) & pmp_pmpcfg[r].read); // Check specific required permissions since the behaviour is different // between Smepmp implementation and original PMP. assign region_perm_check[c][r] = perm_check_wrapper( `ifdef RV_SMEPMP mseccfg, `else 3'b000, `endif pmp_pmpcfg[r], pmp_chan_type[c], `ifdef RV_USER_MODE pmp_priv_mode_eff[c], `else 1'b0, `endif region_basic_perm_check[c][r] ); // Address bits below PMP granularity (which starts at 4 byte) are deliberately unused. logic unused_sigs; assign unused_sigs = ^{region_start_addr[r][PMP_GRANULARITY+2-1:0], pmp_req_addr_i[c][PMP_GRANULARITY+2-1:0]}; end // Once the permission checks of the regions are done, decide if the access is // denied by figuring out the matching region and its permission check. assign pmp_chan_err[c] = access_fault_check( `ifdef RV_SMEPMP mseccfg, `else 3'b000, `endif pmp_chan_type[c], region_match_all[c], `ifdef RV_USER_MODE any_region_enabled, pmp_priv_mode_eff[c], `else 1'b0, 1'b0, `endif region_perm_check[c]); end endmodule // el2_pmp ================================================ FILE: design/el2_veer.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // Function: Top level VeeR core file // Comments: // //******************************************************************************** module el2_veer import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic dbg_rst_l, // rst_vec is supposed to be connected to a constant in the top level /*pragma coverage off*/ input logic [31:1] rst_vec, /*pragma coverage on*/ input logic nmi_int, // nmi_vec is supposed to be connected to a constant in the top level /*pragma coverage off*/ input logic [31:1] nmi_vec, /*pragma coverage on*/ output logic core_rst_l, // This is "rst_l | dbg_rst_l" output logic active_l2clk, output logic free_l2clk, output logic [31:0] trace_rv_i_insn_ip, output logic [31:0] trace_rv_i_address_ip, output logic trace_rv_i_valid_ip, output logic trace_rv_i_exception_ip, output logic [4:0] trace_rv_i_ecause_ip, output logic trace_rv_i_interrupt_ip, output logic [31:0] trace_rv_i_tval_ip, output logic dccm_clk_override, output logic icm_clk_override, output logic dec_tlu_core_ecc_disable, // external halt/run interface input logic i_cpu_halt_req, // Asynchronous Halt request to CPU input logic i_cpu_run_req, // Asynchronous Restart request to CPU output logic o_cpu_halt_ack, // Core Acknowledge to Halt request output logic o_cpu_halt_status, // 1'b1 indicates processor is halted output logic o_cpu_run_ack, // Core Acknowledge to run request output logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request /*pragma coverage off*/ input logic [31:4] core_id, // CORE ID /*pragma coverage on*/ // external MPC halt/run interface input logic mpc_debug_halt_req, // Async halt request input logic mpc_debug_run_req, // Async run request input logic mpc_reset_run_req, // Run/halt after reset output logic mpc_debug_halt_ack, // Halt ack output logic mpc_debug_run_ack, // Run ack output logic debug_brkpt_status, // debug breakpoint output logic dec_tlu_perfcnt0, // toggles when slot0 perf counter 0 has an event inc output logic dec_tlu_perfcnt1, output logic dec_tlu_perfcnt2, output logic dec_tlu_perfcnt3, // DCCM ports output logic dccm_wren, output logic dccm_rden, output logic [pt.DCCM_BITS-1:0] dccm_wr_addr_lo, output logic [pt.DCCM_BITS-1:0] dccm_wr_addr_hi, output logic [pt.DCCM_BITS-1:0] dccm_rd_addr_lo, output logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi, output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo, output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // ICCM ports output logic [pt.ICCM_BITS-1:1] iccm_rw_addr, output logic iccm_wren, output logic iccm_rden, output logic [2:0] iccm_wr_size, output logic [77:0] iccm_wr_data, output logic iccm_buf_correct_ecc, output logic iccm_correction_state, input logic [63:0] iccm_rd_data, input logic [77:0] iccm_rd_data_ecc, // ICache , ITAG ports output logic [31:1] ic_rw_addr, output logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid, output logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en, output logic ic_rd_en, output logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC input logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [25:0] ictag_debug_rd_data,// Debug icache tag. output logic [70:0] ic_debug_wr_data, // Debug wr cache. input logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, input logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, output logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache. output logic ic_sel_premux_data, // Select premux data output logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. output logic ic_debug_rd_en, // Icache debug rd output logic ic_debug_wr_en, // Icache debug wr output logic ic_debug_tag_array, // Debug tag array output logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. input logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, input logic ic_tag_perr, // Icache Tag parity error //-------------------------- LSU AXI signals-------------------------- // AXI Write Channels output logic lsu_axi_awvalid, input logic lsu_axi_awready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid, output logic [31:0] lsu_axi_awaddr, output logic [3:0] lsu_axi_awregion, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [7:0] lsu_axi_awlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_awsize, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [1:0] lsu_axi_awburst, output logic lsu_axi_awlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_awcache, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [2:0] lsu_axi_awprot, output logic [3:0] lsu_axi_awqos, /*pragma coverage on*/ output logic lsu_axi_wvalid, input logic lsu_axi_wready, output logic [63:0] lsu_axi_wdata, output logic [7:0] lsu_axi_wstrb, output logic lsu_axi_wlast, input logic lsu_axi_bvalid, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic lsu_axi_bready, /*pragma coverage on*/ input logic [1:0] lsu_axi_bresp, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid, // AXI Read Channels output logic lsu_axi_arvalid, input logic lsu_axi_arready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid, output logic [31:0] lsu_axi_araddr, output logic [3:0] lsu_axi_arregion, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [7:0] lsu_axi_arlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_arsize, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [1:0] lsu_axi_arburst, output logic lsu_axi_arlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_arcache, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [2:0] lsu_axi_arprot, output logic [3:0] lsu_axi_arqos, /*pragma coverage on*/ input logic lsu_axi_rvalid, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic lsu_axi_rready, /*pragma coverage on*/ input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid, input logic [63:0] lsu_axi_rdata, input logic [1:0] lsu_axi_rresp, input logic lsu_axi_rlast, //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv IFU does not use AXI write channel */ /*pragma coverage off*/ output logic ifu_axi_awvalid, input logic ifu_axi_awready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid, output logic [31:0] ifu_axi_awaddr, output logic [3:0] ifu_axi_awregion, output logic [7:0] ifu_axi_awlen, output logic [2:0] ifu_axi_awsize, output logic [1:0] ifu_axi_awburst, output logic ifu_axi_awlock, output logic [3:0] ifu_axi_awcache, output logic [2:0] ifu_axi_awprot, output logic [3:0] ifu_axi_awqos, output logic ifu_axi_wvalid, input logic ifu_axi_wready, output logic [63:0] ifu_axi_wdata, output logic [7:0] ifu_axi_wstrb, output logic ifu_axi_wlast, input logic ifu_axi_bvalid, output logic ifu_axi_bready, input logic [1:0] ifu_axi_bresp, input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_bid, /*pragma coverage on*/ // AXI Read Channels output logic ifu_axi_arvalid, input logic ifu_axi_arready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid, output logic [31:0] ifu_axi_araddr, output logic [3:0] ifu_axi_arregion, /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv */ /*pragma coverage off*/ output logic [7:0] ifu_axi_arlen, output logic [2:0] ifu_axi_arsize, output logic [1:0] ifu_axi_arburst, output logic ifu_axi_arlock, output logic [3:0] ifu_axi_arcache, output logic [2:0] ifu_axi_arprot, output logic [3:0] ifu_axi_arqos, /*pragma coverage on*/ input logic ifu_axi_rvalid, /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv */ /*pragma coverage off*/ output logic ifu_axi_rready, /*pragma coverage on*/ input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid, input logic [63:0] ifu_axi_rdata, input logic [1:0] ifu_axi_rresp, input logic ifu_axi_rlast, //-------------------------- SB AXI signals-------------------------- // AXI Write Channels output logic sb_axi_awvalid, input logic sb_axi_awready, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [pt.SB_BUS_TAG-1:0] sb_axi_awid, /*pragma coverage on*/ output logic [31:0] sb_axi_awaddr, output logic [3:0] sb_axi_awregion, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [7:0] sb_axi_awlen, /*pragma coverage on*/ output logic [2:0] sb_axi_awsize, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [1:0] sb_axi_awburst, output logic sb_axi_awlock, output logic [3:0] sb_axi_awcache, output logic [2:0] sb_axi_awprot, output logic [3:0] sb_axi_awqos, /*pragma coverage on*/ output logic sb_axi_wvalid, input logic sb_axi_wready, output logic [63:0] sb_axi_wdata, output logic [7:0] sb_axi_wstrb, output logic sb_axi_wlast, input logic sb_axi_bvalid, output logic sb_axi_bready, input logic [1:0] sb_axi_bresp, input logic [pt.SB_BUS_TAG-1:0] sb_axi_bid, // AXI Read Channels output logic sb_axi_arvalid, input logic sb_axi_arready, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [pt.SB_BUS_TAG-1:0] sb_axi_arid, /*pragma coverage on*/ output logic [31:0] sb_axi_araddr, output logic [3:0] sb_axi_arregion, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [7:0] sb_axi_arlen, /*pragma coverage on*/ output logic [2:0] sb_axi_arsize, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [1:0] sb_axi_arburst, output logic sb_axi_arlock, output logic [3:0] sb_axi_arcache, output logic [2:0] sb_axi_arprot, output logic [3:0] sb_axi_arqos, /*pragma coverage on*/ input logic sb_axi_rvalid, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic sb_axi_rready, /*pragma coverage on*/ input logic [pt.SB_BUS_TAG-1:0] sb_axi_rid, input logic [63:0] sb_axi_rdata, input logic [1:0] sb_axi_rresp, input logic sb_axi_rlast, //-------------------------- DMA AXI signals-------------------------- // AXI Write Channels input logic dma_axi_awvalid, output logic dma_axi_awready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid, input logic [31:0] dma_axi_awaddr, input logic [2:0] dma_axi_awsize, input logic [2:0] dma_axi_awprot, input logic [7:0] dma_axi_awlen, input logic [1:0] dma_axi_awburst, input logic dma_axi_wvalid, output logic dma_axi_wready, input logic [63:0] dma_axi_wdata, input logic [7:0] dma_axi_wstrb, input logic dma_axi_wlast, output logic dma_axi_bvalid, input logic dma_axi_bready, output logic [1:0] dma_axi_bresp, output logic [pt.DMA_BUS_TAG-1:0] dma_axi_bid, // AXI Read Channels input logic dma_axi_arvalid, output logic dma_axi_arready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid, input logic [31:0] dma_axi_araddr, input logic [2:0] dma_axi_arsize, input logic [2:0] dma_axi_arprot, input logic [7:0] dma_axi_arlen, input logic [1:0] dma_axi_arburst, output logic dma_axi_rvalid, input logic dma_axi_rready, output logic [pt.DMA_BUS_TAG-1:0] dma_axi_rid, output logic [63:0] dma_axi_rdata, output logic [1:0] dma_axi_rresp, output logic dma_axi_rlast, //// AHB LITE BUS output logic [31:0] haddr, /* exclude signals that are tied to constant value in axi4_to_ahb.sv */ /*pragma coverage off*/ output logic [2:0] hburst, output logic hmastlock, /*pragma coverage on*/ output logic [3:0] hprot, output logic [2:0] hsize, output logic [1:0] htrans, output logic hwrite, input logic [63:0] hrdata, input logic hready, input logic hresp, // LSU AHB Master output logic [31:0] lsu_haddr, /* exclude signals that are tied to constant value in axi4_to_ahb.sv */ /*pragma coverage off*/ output logic [2:0] lsu_hburst, output logic lsu_hmastlock, /*pragma coverage on*/ output logic [3:0] lsu_hprot, output logic [2:0] lsu_hsize, output logic [1:0] lsu_htrans, output logic lsu_hwrite, output logic [63:0] lsu_hwdata, input logic [63:0] lsu_hrdata, input logic lsu_hready, input logic lsu_hresp, //System Bus Debug Master output logic [31:0] sb_haddr, /* exclude signals that are tied to constant value in axi4_to_ahb.sv */ /*pragma coverage off*/ output logic [2:0] sb_hburst, output logic sb_hmastlock, /*pragma coverage on*/ output logic [3:0] sb_hprot, output logic [2:0] sb_hsize, output logic [1:0] sb_htrans, output logic sb_hwrite, output logic [63:0] sb_hwdata, input logic [63:0] sb_hrdata, input logic sb_hready, input logic sb_hresp, // DMA Slave input logic dma_hsel, input logic [31:0] dma_haddr, input logic [2:0] dma_hburst, input logic dma_hmastlock, input logic [3:0] dma_hprot, input logic [2:0] dma_hsize, input logic [1:0] dma_htrans, input logic dma_hwrite, input logic [63:0] dma_hwdata, input logic dma_hreadyin, output logic [63:0] dma_hrdata, output logic dma_hreadyout, output logic dma_hresp, input logic lsu_bus_clk_en, input logic ifu_bus_clk_en, input logic dbg_bus_clk_en, input logic dma_bus_clk_en, input logic dmi_reg_en, // read or write input logic [6:0] dmi_reg_addr, // address of DM register input logic dmi_reg_wr_en, // write instruction input logic [31:0] dmi_reg_wdata, // write data output logic [31:0] dmi_reg_rdata, // ICCM/DCCM ECC status output logic iccm_ecc_single_error, output logic iccm_ecc_double_error, output logic dccm_ecc_single_error, output logic dccm_ecc_double_error, `ifdef RV_LOCKSTEP_REGFILE_ENABLE // Register file el2_regfile_if.veer_rf_src regfile, `endif input logic [pt.PIC_TOTAL_INT:1] extintsrc_req, input logic timer_int, input logic soft_int, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); logic [63:0] hwdata_nc; //---------------------------------------------------------------------- // //---------------------------------------------------------------------- logic ifu_pmu_instr_aligned; logic ifu_ic_error_start; logic ifu_iccm_dma_rd_ecc_single_err; logic ifu_iccm_rd_ecc_single_err; logic ifu_iccm_rd_ecc_double_err; logic lsu_dccm_rd_ecc_single_err; logic lsu_dccm_rd_ecc_double_err; logic lsu_axi_awready_ahb; logic lsu_axi_wready_ahb; logic lsu_axi_bvalid_ahb; logic lsu_axi_bready_ahb; logic [1:0] lsu_axi_bresp_ahb; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid_ahb; logic lsu_axi_arready_ahb; logic lsu_axi_rvalid_ahb; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid_ahb; logic [63:0] lsu_axi_rdata_ahb; logic [1:0] lsu_axi_rresp_ahb; logic lsu_axi_rlast_ahb; logic lsu_axi_awready_int; logic lsu_axi_wready_int; logic lsu_axi_bvalid_int; logic [1:0] lsu_axi_bresp_int; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid_int; logic lsu_axi_arready_int; logic lsu_axi_rvalid_int; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid_int; logic [63:0] lsu_axi_rdata_int; logic [1:0] lsu_axi_rresp_int; logic lsu_axi_rlast_int; logic ifu_axi_awready_ahb; logic ifu_axi_wready_ahb; logic ifu_axi_bvalid_ahb; logic ifu_axi_bready_ahb; logic [1:0] ifu_axi_bresp_ahb; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_bid_ahb; logic ifu_axi_arready_ahb; logic ifu_axi_rvalid_ahb; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid_ahb; logic [63:0] ifu_axi_rdata_ahb; logic [1:0] ifu_axi_rresp_ahb; logic ifu_axi_rlast_ahb; logic ifu_axi_awready_int; logic ifu_axi_wready_int; logic ifu_axi_bvalid_int; logic [1:0] ifu_axi_bresp_int; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_bid_int; logic ifu_axi_arready_int; logic ifu_axi_rvalid_int; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid_int; logic [63:0] ifu_axi_rdata_int; logic [1:0] ifu_axi_rresp_int; logic ifu_axi_rlast_int; logic sb_axi_awready_ahb; logic sb_axi_wready_ahb; logic sb_axi_bvalid_ahb; logic sb_axi_bready_ahb; logic [1:0] sb_axi_bresp_ahb; logic [pt.SB_BUS_TAG-1:0] sb_axi_bid_ahb; logic sb_axi_arready_ahb; logic sb_axi_rvalid_ahb; logic [pt.SB_BUS_TAG-1:0] sb_axi_rid_ahb; logic [63:0] sb_axi_rdata_ahb; logic [1:0] sb_axi_rresp_ahb; logic sb_axi_rlast_ahb; logic sb_axi_awready_int; logic sb_axi_wready_int; logic sb_axi_bvalid_int; logic [1:0] sb_axi_bresp_int; logic [pt.SB_BUS_TAG-1:0] sb_axi_bid_int; logic sb_axi_arready_int; logic sb_axi_rvalid_int; logic [pt.SB_BUS_TAG-1:0] sb_axi_rid_int; logic [63:0] sb_axi_rdata_int; logic [1:0] sb_axi_rresp_int; logic sb_axi_rlast_int; logic dma_axi_awvalid_ahb; /* exclude signals that are tied to constant value in ahb_to_axi4.sv */ /*pragma coverage off*/ logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid_ahb; /*pragma coverage on*/ logic [31:0] dma_axi_awaddr_ahb; logic [2:0] dma_axi_awsize_ahb; /* exclude signals that are tied to constant value in ahb_to_axi4.sv */ /*pragma coverage off*/ logic [2:0] dma_axi_awprot_ahb; logic [7:0] dma_axi_awlen_ahb; logic [1:0] dma_axi_awburst_ahb; /*pragma coverage on*/ logic dma_axi_wvalid_ahb; logic [63:0] dma_axi_wdata_ahb; logic [7:0] dma_axi_wstrb_ahb; /* exclude signals that are tied to constant value in ahb_to_axi4.sv */ /*pragma coverage off*/ logic dma_axi_wlast_ahb; logic dma_axi_bready_ahb; /*pragma coverage on*/ logic dma_axi_arvalid_ahb; /* exclude signals that are tied to constant value in ahb_to_axi4.sv */ /*pragma coverage off*/ logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid_ahb; /*pragma coverage on*/ logic [31:0] dma_axi_araddr_ahb; logic [2:0] dma_axi_arsize_ahb; /* exclude signals that are tied to constant value in ahb_to_axi4.sv */ /*pragma coverage off*/ logic [2:0] dma_axi_arprot_ahb; logic [7:0] dma_axi_arlen_ahb; logic [1:0] dma_axi_arburst_ahb; logic dma_axi_rready_ahb; /*pragma coverage on*/ logic dma_axi_awvalid_int; logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid_int; logic [31:0] dma_axi_awaddr_int; logic [2:0] dma_axi_awsize_int; logic [2:0] dma_axi_awprot_int; logic [7:0] dma_axi_awlen_int; logic [1:0] dma_axi_awburst_int; logic dma_axi_wvalid_int; logic [63:0] dma_axi_wdata_int; logic [7:0] dma_axi_wstrb_int; logic dma_axi_wlast_int; logic dma_axi_bready_int; logic dma_axi_arvalid_int; logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid_int; logic [31:0] dma_axi_araddr_int; logic [2:0] dma_axi_arsize_int; logic [2:0] dma_axi_arprot_int; logic [7:0] dma_axi_arlen_int; logic [1:0] dma_axi_arburst_int; logic dma_axi_rready_int; // Icache debug logic [70:0] ifu_ic_debug_rd_data; // diagnostic icache read data logic ifu_ic_debug_rd_data_valid; // diagnostic icache read data valid el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt; // packet of DICAWICS, DICAD0/1, DICAGO info for icache diagnostics logic dec_i0_rs1_en_d; logic dec_i0_rs2_en_d; logic [31:0] gpr_i0_rs1_d; logic [31:0] gpr_i0_rs2_d; logic [31:0] dec_i0_result_r; logic [31:0] exu_i0_result_x; logic [31:1] exu_i0_pc_x; logic [31:1] exu_npc_r; el2_alu_pkt_t i0_ap; // Trigger signals el2_trigger_pkt_t [3:0] trigger_pkt_any; logic [3:0] lsu_trigger_match_m; logic [31:0] dec_i0_immed_d; logic [12:1] dec_i0_br_immed_d; logic dec_i0_select_pc_d; logic [31:1] dec_i0_pc_d; logic [3:0] dec_i0_rs1_bypass_en_d; logic [3:0] dec_i0_rs2_bypass_en_d; logic dec_i0_alu_decode_d; logic dec_i0_branch_d; logic ifu_miss_state_idle; logic dec_tlu_flush_noredir_r; logic dec_tlu_flush_leak_one_r; logic dec_tlu_flush_err_r; logic ifu_i0_valid; logic [31:0] ifu_i0_instr; logic [31:1] ifu_i0_pc; logic exu_flush_final; logic [31:1] exu_flush_path_final; logic [31:0] exu_lsu_rs1_d; logic [31:0] exu_lsu_rs2_d; el2_lsu_pkt_t lsu_p; logic dec_qual_lsu_d; logic dec_lsu_valid_raw_d; logic [11:0] dec_lsu_offset_d; logic [31:0] lsu_result_m; logic [31:0] lsu_result_corr_r; // This is the ECC corrected data going to RF logic lsu_single_ecc_error_incr; // Increment the ecc counter el2_lsu_error_pkt_t lsu_error_pkt_r; logic lsu_imprecise_error_load_any; logic lsu_imprecise_error_store_any; logic [31:0] lsu_imprecise_error_addr_any; logic lsu_load_stall_any; // This is for blocking loads logic lsu_store_stall_any; // This is for blocking stores logic lsu_idle_any; // doesn't include DMA logic lsu_active; // lsu is active. used for clock logic [31:1] lsu_fir_addr; // fast interrupt address logic [1:0] lsu_fir_error; // Error during fast interrupt lookup // Non-blocking loads logic lsu_nonblock_load_valid_m; logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_m; logic lsu_nonblock_load_inv_r; logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_r; logic lsu_nonblock_load_data_valid; logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag; logic [31:0] lsu_nonblock_load_data; logic dec_csr_ren_d; logic [31:0] dec_csr_rddata_d; logic [31:0] exu_csr_rs1_x; logic dec_tlu_i0_commit_cmt; logic dec_tlu_flush_lower_r; logic dec_tlu_flush_lower_wb; logic dec_tlu_i0_kill_writeb_r; // I0 is flushed, don't writeback any results to arch state logic dec_tlu_fence_i_r; // flush is a fence_i rfnpc, flush icache logic [31:1] dec_tlu_flush_path_r; logic [31:0] dec_tlu_mrac_ff; // CSR for memory region control logic ifu_i0_pc4; el2_mul_pkt_t mul_p; el2_div_pkt_t div_p; logic dec_div_cancel; logic [31:0] exu_div_result; logic exu_div_wren; logic dec_i0_decode_d; logic [31:1] pred_correct_npc_x; el2_br_tlu_pkt_t dec_tlu_br0_r_pkt; el2_predict_pkt_t exu_mp_pkt; logic [pt.BHT_GHR_SIZE-1:0] exu_mp_eghr; logic [pt.BHT_GHR_SIZE-1:0] exu_mp_fghr; logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_mp_index; logic [pt.BTB_BTAG_SIZE-1:0] exu_mp_btag; logic [pt.BHT_GHR_SIZE-1:0] exu_i0_br_fghr_r; logic [1:0] exu_i0_br_hist_r; logic exu_i0_br_error_r; logic exu_i0_br_start_error_r; logic exu_i0_br_valid_r; logic exu_i0_br_mp_r; logic exu_i0_br_middle_r; logic exu_i0_br_way_r; logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_i0_br_index_r; logic dma_dccm_req; logic dma_iccm_req; logic [2:0] dma_mem_tag; logic [31:0] dma_mem_addr; logic [2:0] dma_mem_sz; logic dma_mem_write; logic [63:0] dma_mem_wdata; logic dccm_dma_rvalid; logic dccm_dma_ecc_error; logic [2:0] dccm_dma_rtag; logic [63:0] dccm_dma_rdata; logic iccm_dma_rvalid; logic iccm_dma_ecc_error; logic [2:0] iccm_dma_rtag; logic [63:0] iccm_dma_rdata; logic dma_dccm_stall_any; // Stall the ld/st in decode if asserted logic dma_iccm_stall_any; // Stall the fetch logic dccm_ready; logic iccm_ready; logic dma_pmu_dccm_read; logic dma_pmu_dccm_write; logic dma_pmu_any_read; logic dma_pmu_any_write; logic ifu_i0_icaf; logic [1:0] ifu_i0_icaf_type; logic ifu_i0_icaf_second; logic ifu_i0_dbecc; logic iccm_dma_sb_error; el2_br_pkt_t i0_brp; logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index; logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr; logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag; logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index; logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index; // Fully associative btb error index el2_predict_pkt_t dec_i0_predict_p_d; logic [pt.BHT_GHR_SIZE-1:0] i0_predict_fghr_d; // DEC predict fghr logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] i0_predict_index_d; // DEC predict index logic [pt.BTB_BTAG_SIZE-1:0] i0_predict_btag_d; // DEC predict branch tag // PIC ports logic picm_wren; logic picm_rden; logic picm_mken; logic [31:0] picm_rdaddr; logic [31:0] picm_wraddr; logic [31:0] picm_wr_data; logic [31:0] picm_rd_data; // feature disable from mfdc logic dec_tlu_external_ldfwd_disable; // disable external load forwarding logic dec_tlu_bpred_disable; logic dec_tlu_wb_coalescing_disable; logic dec_tlu_sideeffect_posted_disable; logic [2:0] dec_tlu_dma_qos_prty; // DMA QoS priority coming from MFDC [18:16] // clock gating overrides from mcgc logic dec_tlu_misc_clk_override; logic dec_tlu_ifu_clk_override; logic dec_tlu_lsu_clk_override; logic dec_tlu_bus_clk_override; logic dec_tlu_pic_clk_override; logic dec_tlu_dccm_clk_override; logic dec_tlu_icm_clk_override; logic dec_tlu_picio_clk_override; assign dccm_clk_override = dec_tlu_dccm_clk_override; // dccm memory assign icm_clk_override = dec_tlu_icm_clk_override; // icache/iccm memory // PMP Signals el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES]; logic [31:0] pmp_pmpaddr [pt.PMP_ENTRIES]; logic [31:0] pmp_chan_addr [3]; el2_pmp_type_pkt_t pmp_chan_type [3]; logic pmp_chan_err [3]; logic [31:1] ifu_pmp_addr; logic ifu_pmp_error; logic [31:0] lsu_pmp_addr_start; logic lsu_pmp_error_start; logic [31:0] lsu_pmp_addr_end; logic lsu_pmp_error_end; logic lsu_pmp_we; logic lsu_pmp_re; // -----------------------DEBUG START ------------------------------- logic [31:0] dbg_cmd_addr; // the address of the debug command to used by the core logic [31:0] dbg_cmd_wrdata; // If the debug command is a write command, this has the data to be written to the CSR/GPR logic dbg_cmd_valid; // commad is being driven by the dbg module. One pulse. Only dirven when core_halted has been seen logic dbg_cmd_write; // 1: write command; 0: read_command logic [1:0] dbg_cmd_type; // 0:gpr 1:csr 2: memory logic [1:0] dbg_cmd_size; // size of the abstract mem access debug command logic dbg_halt_req; // Sticky signal indicating that the debug module wants to start the entering of debug mode ( start the halting sequence ) logic dbg_resume_req; // Sticky signal indicating that the debug module wants to resume from debug mode logic dbg_core_rst_l; // Core reset from DM logic core_dbg_cmd_done; // Final muxed cmd done to debug logic core_dbg_cmd_fail; // Final muxed cmd done to debug logic [31:0] core_dbg_rddata; // Final muxed cmd done to debug logic dma_dbg_cmd_done; // Abstarct memory command sent to dma is done logic dma_dbg_cmd_fail; // Abstarct memory command sent to dma failed logic [31:0] dma_dbg_rddata; // Read data for abstract memory access logic dbg_dma_bubble; // Debug needs a bubble to send a valid logic dma_dbg_ready; // DMA is ready to accept debug request logic [31:0] dec_dbg_rddata; // The core drives this data ( intercepts the pipe and sends it here ) logic dec_dbg_cmd_done; // This will be treated like a valid signal logic dec_dbg_cmd_fail; // Abstract command failed logic dec_tlu_mpc_halted_only; // Only halted due to MPC logic dec_tlu_dbg_halted; // The core has finished the queiscing sequence. Sticks this signal high logic dec_tlu_resume_ack; logic dec_tlu_debug_mode; // Core is in debug mode logic dec_debug_wdata_rs1_d; logic dec_tlu_force_halt; // halt has been forced logic [1:0] dec_data_en; logic [1:0] dec_ctl_en; // PMU Signals logic exu_pmu_i0_br_misp; logic exu_pmu_i0_br_ataken; logic exu_pmu_i0_pc4; logic lsu_pmu_load_external_m; logic lsu_pmu_store_external_m; logic lsu_pmu_misaligned_m; logic lsu_pmu_bus_trxn; logic lsu_pmu_bus_misaligned; logic lsu_pmu_bus_error; logic lsu_pmu_bus_busy; logic ifu_pmu_fetch_stall; logic ifu_pmu_ic_miss; logic ifu_pmu_ic_hit; logic ifu_pmu_bus_error; logic ifu_pmu_bus_busy; logic ifu_pmu_bus_trxn; logic active_state; logic free_clk; logic active_clk; logic dec_pause_state_cg; logic lsu_nonblock_load_data_error; logic [15:0] ifu_i0_cinst; // fast interrupt logic [31:2] dec_tlu_meihap; logic dec_extint_stall; el2_trace_pkt_t trace_rv_trace_pkt; logic lsu_fastint_stall_any; logic [7:0] pic_claimid; logic [3:0] pic_pl, dec_tlu_meicurpl, dec_tlu_meipt; logic mexintpend; logic mhwakeup; logic dma_active; logic pause_state; logic halt_state; logic dec_tlu_core_empty; assign pause_state = dec_pause_state_cg & ~(dma_active | lsu_active) & dec_tlu_core_empty; assign halt_state = o_cpu_halt_status & ~(dma_active | lsu_active); assign active_state = (~(halt_state | pause_state) | dec_tlu_flush_lower_r | dec_tlu_flush_lower_wb) | dec_tlu_misc_clk_override; rvoclkhdr free_cg2 ( .clk(clk), .en(1'b1), .l1clk(free_l2clk), .* ); rvoclkhdr active_cg2 ( .clk(clk), .en(active_state), .l1clk(active_l2clk), .* ); // all other clock headers are 1st level rvoclkhdr free_cg1 ( .clk(free_l2clk), .en(1'b1), .l1clk(free_clk), .* ); rvoclkhdr active_cg1 ( .clk(active_l2clk), .en(1'b1), .l1clk(active_clk), .* ); assign core_dbg_cmd_done = dma_dbg_cmd_done | dec_dbg_cmd_done; assign core_dbg_cmd_fail = dma_dbg_cmd_fail | dec_dbg_cmd_fail; assign core_dbg_rddata[31:0] = dma_dbg_cmd_done ? dma_dbg_rddata[31:0] : dec_dbg_rddata[31:0]; el2_dbg #(.pt(pt)) dbg ( .rst_l(core_rst_l), .clk(free_l2clk), .clk_override(dec_tlu_misc_clk_override), // AXI signals .sb_axi_awready(sb_axi_awready_int), .sb_axi_wready(sb_axi_wready_int), .sb_axi_bvalid(sb_axi_bvalid_int), .sb_axi_bresp(sb_axi_bresp_int[1:0]), .sb_axi_arready(sb_axi_arready_int), .sb_axi_rvalid(sb_axi_rvalid_int), .sb_axi_rdata(sb_axi_rdata_int[63:0]), .sb_axi_rresp(sb_axi_rresp_int[1:0]), .* ); `ifdef RV_ASSERT_ON assert_fetch_indbghalt: assert #0 (~(ifu.ifc_fetch_req_f & dec.tlu.dbg_tlu_halted_f & ~dec.tlu.dcsr_single_step_running)) else $display("ERROR: Fetching in dBG halt!"); `endif // ----------------- DEBUG END ----------------------------- assign core_rst_l = rst_l & (dbg_core_rst_l | scan_mode); `ifdef RV_USER_MODE // Operating privilege mode, 0 - machine, 1 - user logic priv_mode; // Effective privilege mode, 0 - machine, 1 - user (driven in el2_dec_tlu_ctl.sv) logic priv_mode_eff; // Next privilege mode logic priv_mode_ns; el2_mseccfg_pkt_t mseccfg; // mseccfg CSR for PMP `endif // fetch el2_ifu #(.pt(pt)) ifu ( .clk(active_l2clk), .rst_l(core_rst_l), .dec_tlu_flush_err_wb (dec_tlu_flush_err_r ), .dec_tlu_flush_noredir_wb (dec_tlu_flush_noredir_r ), .dec_tlu_fence_i_wb (dec_tlu_fence_i_r ), .dec_tlu_flush_leak_one_wb (dec_tlu_flush_leak_one_r ), .dec_tlu_flush_lower_wb (dec_tlu_flush_lower_r ), // AXI signals .ifu_axi_arready(ifu_axi_arready_int), .ifu_axi_rvalid(ifu_axi_rvalid_int), .ifu_axi_rid(ifu_axi_rid_int[pt.IFU_BUS_TAG-1:0]), .ifu_axi_rdata(ifu_axi_rdata_int[63:0]), .ifu_axi_rresp(ifu_axi_rresp_int[1:0]), .* ); assign iccm_ecc_single_error = ifu_iccm_rd_ecc_single_err || ifu_iccm_dma_rd_ecc_single_err; assign iccm_ecc_double_error = ifu_iccm_rd_ecc_double_err; el2_dec #(.pt(pt)) dec ( .clk(active_l2clk), .dbg_cmd_wrdata(dbg_cmd_wrdata[1:0]), .rst_l(core_rst_l), .* ); el2_exu #(.pt(pt)) exu ( .clk(active_l2clk), .rst_l(core_rst_l), .* ); el2_lsu #(.pt(pt)) lsu ( .clk(active_l2clk), .rst_l(core_rst_l), .clk_override(dec_tlu_lsu_clk_override), .dec_tlu_i0_kill_writeb_r(dec_tlu_i0_kill_writeb_r), // AXI signals .lsu_axi_awready(lsu_axi_awready_int), .lsu_axi_wready(lsu_axi_wready_int), .lsu_axi_bvalid(lsu_axi_bvalid_int), .lsu_axi_bid(lsu_axi_bid_int[pt.LSU_BUS_TAG-1:0]), .lsu_axi_bresp(lsu_axi_bresp_int[1:0]), .lsu_axi_arready(lsu_axi_arready_int), .lsu_axi_rvalid(lsu_axi_rvalid_int), .lsu_axi_rid(lsu_axi_rid_int[pt.LSU_BUS_TAG-1:0]), .lsu_axi_rdata(lsu_axi_rdata_int[63:0]), .lsu_axi_rresp(lsu_axi_rresp_int[1:0]), .lsu_axi_rlast(lsu_axi_rlast_int), .* ); assign dccm_ecc_single_error = lsu_dccm_rd_ecc_single_err; assign dccm_ecc_double_error = lsu_dccm_rd_ecc_double_err; el2_pic_ctrl #(.pt(pt)) pic_ctrl_inst ( .clk(free_l2clk), .clk_override(dec_tlu_pic_clk_override), .io_clk_override(dec_tlu_picio_clk_override), .picm_mken (picm_mken), .extintsrc_req({extintsrc_req[pt.PIC_TOTAL_INT:1],1'b0}), .pl(pic_pl[3:0]), .claimid(pic_claimid[7:0]), .meicurpl(dec_tlu_meicurpl[3:0]), .meipt(dec_tlu_meipt[3:0]), .rst_l(core_rst_l), .*); el2_dma_ctrl #(.pt(pt)) dma_ctrl ( .clk(free_l2clk), .rst_l(core_rst_l), .clk_override(dec_tlu_misc_clk_override), // AXI signals .dma_axi_awvalid(dma_axi_awvalid_int), .dma_axi_awid(dma_axi_awid_int[pt.DMA_BUS_TAG-1:0]), .dma_axi_awaddr(dma_axi_awaddr_int[31:0]), .dma_axi_awsize(dma_axi_awsize_int[2:0]), .dma_axi_wvalid(dma_axi_wvalid_int), .dma_axi_wdata(dma_axi_wdata_int[63:0]), .dma_axi_wstrb(dma_axi_wstrb_int[7:0]), .dma_axi_bready(dma_axi_bready_int), .dma_axi_arvalid(dma_axi_arvalid_int), .dma_axi_arid(dma_axi_arid_int[pt.DMA_BUS_TAG-1:0]), .dma_axi_araddr(dma_axi_araddr_int[31:0]), .dma_axi_arsize(dma_axi_arsize_int[2:0]), .dma_axi_rready(dma_axi_rready_int), .* ); assign pmp_chan_addr[0] = {ifu_pmp_addr, 1'b0}; assign pmp_chan_type[0] = EXEC; assign ifu_pmp_error = pmp_chan_err[0]; assign pmp_chan_addr[1] = lsu_pmp_addr_start; assign pmp_chan_type[1] = lsu_pmp_we ? WRITE : (lsu_pmp_re ? READ : NONE); assign lsu_pmp_error_start = pmp_chan_err[1]; assign pmp_chan_addr[2] = lsu_pmp_addr_end; assign pmp_chan_type[2] = lsu_pmp_we ? WRITE : (lsu_pmp_re ? READ : NONE); assign lsu_pmp_error_end = pmp_chan_err[2]; el2_pmp #( .PMP_CHANNELS(3), .pt(pt) ) pmp ( .clk (active_l2clk), .rst_l(core_rst_l), .* ); if (pt.BUILD_AHB_LITE == 1) begin: Gen_AXI_To_AHB // AXI4 -> AHB Gasket for LSU axi4_to_ahb #(.pt(pt), .TAG(pt.LSU_BUS_TAG)) lsu_axi4_to_ahb ( .clk(free_l2clk), .free_clk(free_clk), .rst_l(core_rst_l), .clk_override(dec_tlu_bus_clk_override), .bus_clk_en(lsu_bus_clk_en), .dec_tlu_force_halt(dec_tlu_force_halt), // AXI Write Channels .axi_awvalid(lsu_axi_awvalid), .axi_awready(lsu_axi_awready_ahb), .axi_awid(lsu_axi_awid[pt.LSU_BUS_TAG-1:0]), .axi_awaddr(lsu_axi_awaddr[31:0]), .axi_awsize(lsu_axi_awsize[2:0]), .axi_awprot(lsu_axi_awprot[2:0]), .axi_wvalid(lsu_axi_wvalid), .axi_wready(lsu_axi_wready_ahb), .axi_wdata(lsu_axi_wdata[63:0]), .axi_wstrb(lsu_axi_wstrb[7:0]), .axi_wlast(lsu_axi_wlast), .axi_bvalid(lsu_axi_bvalid_ahb), .axi_bready(lsu_axi_bready), .axi_bresp(lsu_axi_bresp_ahb[1:0]), .axi_bid(lsu_axi_bid_ahb[pt.LSU_BUS_TAG-1:0]), // AXI Read Channels .axi_arvalid(lsu_axi_arvalid), .axi_arready(lsu_axi_arready_ahb), .axi_arid(lsu_axi_arid[pt.LSU_BUS_TAG-1:0]), .axi_araddr(lsu_axi_araddr[31:0]), .axi_arsize(lsu_axi_arsize[2:0]), .axi_arprot(lsu_axi_arprot[2:0]), .axi_rvalid(lsu_axi_rvalid_ahb), .axi_rready(lsu_axi_rready), .axi_rid(lsu_axi_rid_ahb[pt.LSU_BUS_TAG-1:0]), .axi_rdata(lsu_axi_rdata_ahb[63:0]), .axi_rresp(lsu_axi_rresp_ahb[1:0]), .axi_rlast(lsu_axi_rlast_ahb), // AHB-LITE signals .ahb_haddr(lsu_haddr[31:0]), .ahb_hburst(lsu_hburst), .ahb_hmastlock(lsu_hmastlock), .ahb_hprot(lsu_hprot[3:0]), .ahb_hsize(lsu_hsize[2:0]), .ahb_htrans(lsu_htrans[1:0]), .ahb_hwrite(lsu_hwrite), .ahb_hwdata(lsu_hwdata[63:0]), .ahb_hrdata(lsu_hrdata[63:0]), .ahb_hready(lsu_hready), .ahb_hresp(lsu_hresp), .* ); axi4_to_ahb #(.pt(pt), .TAG(pt.IFU_BUS_TAG)) ifu_axi4_to_ahb ( .clk(free_l2clk), .free_clk(free_clk), .rst_l(core_rst_l), .clk_override(dec_tlu_bus_clk_override), .bus_clk_en(ifu_bus_clk_en), .dec_tlu_force_halt(dec_tlu_force_halt), // AHB-Lite signals .ahb_haddr(haddr[31:0]), .ahb_hburst(hburst), .ahb_hmastlock(hmastlock), .ahb_hprot(hprot[3:0]), .ahb_hsize(hsize[2:0]), .ahb_htrans(htrans[1:0]), .ahb_hwrite(hwrite), .ahb_hwdata(hwdata_nc[63:0]), .ahb_hrdata(hrdata[63:0]), .ahb_hready(hready), .ahb_hresp(hresp), // AXI Write Channels .axi_awvalid(ifu_axi_awvalid), .axi_awready(ifu_axi_awready_ahb), .axi_awid(ifu_axi_awid[pt.IFU_BUS_TAG-1:0]), .axi_awaddr(ifu_axi_awaddr[31:0]), .axi_awsize(ifu_axi_awsize[2:0]), .axi_awprot(ifu_axi_awprot[2:0]), .axi_wvalid(ifu_axi_wvalid), .axi_wready(ifu_axi_wready_ahb), .axi_wdata(ifu_axi_wdata[63:0]), .axi_wstrb(ifu_axi_wstrb[7:0]), .axi_wlast(ifu_axi_wlast), .axi_bvalid(ifu_axi_bvalid_ahb), .axi_bready(1'b1), .axi_bresp(ifu_axi_bresp_ahb[1:0]), .axi_bid(ifu_axi_bid_ahb[pt.IFU_BUS_TAG-1:0]), // AXI Read Channels .axi_arvalid(ifu_axi_arvalid), .axi_arready(ifu_axi_arready_ahb), .axi_arid(ifu_axi_arid[pt.IFU_BUS_TAG-1:0]), .axi_araddr(ifu_axi_araddr[31:0]), .axi_arsize(ifu_axi_arsize[2:0]), .axi_arprot(ifu_axi_arprot[2:0]), .axi_rvalid(ifu_axi_rvalid_ahb), .axi_rready(ifu_axi_rready), .axi_rid(ifu_axi_rid_ahb[pt.IFU_BUS_TAG-1:0]), .axi_rdata(ifu_axi_rdata_ahb[63:0]), .axi_rresp(ifu_axi_rresp_ahb[1:0]), .axi_rlast(ifu_axi_rlast_ahb), .* ); // AXI4 -> AHB Gasket for System Bus axi4_to_ahb #(.pt(pt), .TAG(pt.SB_BUS_TAG)) sb_axi4_to_ahb ( .clk(free_l2clk), .free_clk(free_clk), .rst_l(dbg_rst_l), .clk_override(dec_tlu_bus_clk_override), .bus_clk_en(dbg_bus_clk_en), .dec_tlu_force_halt(1'b0), // AXI Write Channels .axi_awvalid(sb_axi_awvalid), .axi_awready(sb_axi_awready_ahb), .axi_awid(sb_axi_awid[pt.SB_BUS_TAG-1:0]), .axi_awaddr(sb_axi_awaddr[31:0]), .axi_awsize(sb_axi_awsize[2:0]), .axi_awprot(sb_axi_awprot[2:0]), .axi_wvalid(sb_axi_wvalid), .axi_wready(sb_axi_wready_ahb), .axi_wdata(sb_axi_wdata[63:0]), .axi_wstrb(sb_axi_wstrb[7:0]), .axi_wlast(sb_axi_wlast), .axi_bvalid(sb_axi_bvalid_ahb), .axi_bready(sb_axi_bready), .axi_bresp(sb_axi_bresp_ahb[1:0]), .axi_bid(sb_axi_bid_ahb[pt.SB_BUS_TAG-1:0]), // AXI Read Channels .axi_arvalid(sb_axi_arvalid), .axi_arready(sb_axi_arready_ahb), .axi_arid(sb_axi_arid[pt.SB_BUS_TAG-1:0]), .axi_araddr(sb_axi_araddr[31:0]), .axi_arsize(sb_axi_arsize[2:0]), .axi_arprot(sb_axi_arprot[2:0]), .axi_rvalid(sb_axi_rvalid_ahb), .axi_rready(sb_axi_rready), .axi_rid(sb_axi_rid_ahb[pt.SB_BUS_TAG-1:0]), .axi_rdata(sb_axi_rdata_ahb[63:0]), .axi_rresp(sb_axi_rresp_ahb[1:0]), .axi_rlast(sb_axi_rlast_ahb), // AHB-LITE signals .ahb_haddr(sb_haddr[31:0]), .ahb_hburst(sb_hburst), .ahb_hmastlock(sb_hmastlock), .ahb_hprot(sb_hprot[3:0]), .ahb_hsize(sb_hsize[2:0]), .ahb_htrans(sb_htrans[1:0]), .ahb_hwrite(sb_hwrite), .ahb_hwdata(sb_hwdata[63:0]), .ahb_hrdata(sb_hrdata[63:0]), .ahb_hready(sb_hready), .ahb_hresp(sb_hresp), .* ); //AHB -> AXI4 Gasket for DMA ahb_to_axi4 #(.pt(pt), .TAG(pt.DMA_BUS_TAG)) dma_ahb_to_axi4 ( .clk(free_l2clk), .rst_l(core_rst_l), .clk_override(dec_tlu_bus_clk_override), .bus_clk_en(dma_bus_clk_en), // AXI Write Channels .axi_awvalid(dma_axi_awvalid_ahb), .axi_awready(dma_axi_awready), .axi_awid(dma_axi_awid_ahb[pt.DMA_BUS_TAG-1:0]), .axi_awaddr(dma_axi_awaddr_ahb[31:0]), .axi_awsize(dma_axi_awsize_ahb[2:0]), .axi_awprot(dma_axi_awprot_ahb[2:0]), .axi_awlen(dma_axi_awlen_ahb[7:0]), .axi_awburst(dma_axi_awburst_ahb[1:0]), .axi_wvalid(dma_axi_wvalid_ahb), .axi_wready(dma_axi_wready), .axi_wdata(dma_axi_wdata_ahb[63:0]), .axi_wstrb(dma_axi_wstrb_ahb[7:0]), .axi_wlast(dma_axi_wlast_ahb), .axi_bvalid(dma_axi_bvalid), .axi_bready(dma_axi_bready_ahb), .axi_bresp(dma_axi_bresp[1:0]), .axi_bid(dma_axi_bid[pt.DMA_BUS_TAG-1:0]), // AXI Read Channels .axi_arvalid(dma_axi_arvalid_ahb), .axi_arready(dma_axi_arready), .axi_arid(dma_axi_arid_ahb[pt.DMA_BUS_TAG-1:0]), .axi_araddr(dma_axi_araddr_ahb[31:0]), .axi_arsize(dma_axi_arsize_ahb[2:0]), .axi_arprot(dma_axi_arprot_ahb[2:0]), .axi_arlen(dma_axi_arlen_ahb[7:0]), .axi_arburst(dma_axi_arburst_ahb[1:0]), .axi_rvalid(dma_axi_rvalid), .axi_rready(dma_axi_rready_ahb), .axi_rid(dma_axi_rid[pt.DMA_BUS_TAG-1:0]), .axi_rdata(dma_axi_rdata[63:0]), .axi_rresp(dma_axi_rresp[1:0]), // AHB signals .ahb_haddr(dma_haddr[31:0]), .ahb_hburst(dma_hburst), .ahb_hmastlock(dma_hmastlock), .ahb_hprot(dma_hprot[3:0]), .ahb_hsize(dma_hsize[2:0]), .ahb_htrans(dma_htrans[1:0]), .ahb_hwrite(dma_hwrite), .ahb_hwdata(dma_hwdata[63:0]), .ahb_hrdata(dma_hrdata[63:0]), .ahb_hreadyout(dma_hreadyout), .ahb_hresp(dma_hresp), .ahb_hreadyin(dma_hreadyin), .ahb_hsel(dma_hsel), .* ); end // Drive the final AXI inputs assign lsu_axi_awready_int = pt.BUILD_AHB_LITE ? lsu_axi_awready_ahb : lsu_axi_awready; assign lsu_axi_wready_int = pt.BUILD_AHB_LITE ? lsu_axi_wready_ahb : lsu_axi_wready; assign lsu_axi_bvalid_int = pt.BUILD_AHB_LITE ? lsu_axi_bvalid_ahb : lsu_axi_bvalid; assign lsu_axi_bresp_int[1:0] = pt.BUILD_AHB_LITE ? lsu_axi_bresp_ahb[1:0] : lsu_axi_bresp[1:0]; assign lsu_axi_bid_int[pt.LSU_BUS_TAG-1:0] = pt.BUILD_AHB_LITE ? lsu_axi_bid_ahb[pt.LSU_BUS_TAG-1:0] : lsu_axi_bid[pt.LSU_BUS_TAG-1:0]; assign lsu_axi_arready_int = pt.BUILD_AHB_LITE ? lsu_axi_arready_ahb : lsu_axi_arready; assign lsu_axi_rvalid_int = pt.BUILD_AHB_LITE ? lsu_axi_rvalid_ahb : lsu_axi_rvalid; assign lsu_axi_rid_int[pt.LSU_BUS_TAG-1:0] = pt.BUILD_AHB_LITE ? lsu_axi_rid_ahb[pt.LSU_BUS_TAG-1:0] : lsu_axi_rid[pt.LSU_BUS_TAG-1:0]; assign lsu_axi_rdata_int[63:0] = pt.BUILD_AHB_LITE ? lsu_axi_rdata_ahb[63:0] : lsu_axi_rdata[63:0]; assign lsu_axi_rresp_int[1:0] = pt.BUILD_AHB_LITE ? lsu_axi_rresp_ahb[1:0] : lsu_axi_rresp[1:0]; assign lsu_axi_rlast_int = pt.BUILD_AHB_LITE ? lsu_axi_rlast_ahb : lsu_axi_rlast; assign ifu_axi_awready_int = pt.BUILD_AHB_LITE ? ifu_axi_awready_ahb : ifu_axi_awready; assign ifu_axi_wready_int = pt.BUILD_AHB_LITE ? ifu_axi_wready_ahb : ifu_axi_wready; assign ifu_axi_bvalid_int = pt.BUILD_AHB_LITE ? ifu_axi_bvalid_ahb : ifu_axi_bvalid; assign ifu_axi_bresp_int[1:0] = pt.BUILD_AHB_LITE ? ifu_axi_bresp_ahb[1:0] : ifu_axi_bresp[1:0]; assign ifu_axi_bid_int[pt.IFU_BUS_TAG-1:0] = pt.BUILD_AHB_LITE ? ifu_axi_bid_ahb[pt.IFU_BUS_TAG-1:0] : ifu_axi_bid[pt.IFU_BUS_TAG-1:0]; assign ifu_axi_arready_int = pt.BUILD_AHB_LITE ? ifu_axi_arready_ahb : ifu_axi_arready; assign ifu_axi_rvalid_int = pt.BUILD_AHB_LITE ? ifu_axi_rvalid_ahb : ifu_axi_rvalid; assign ifu_axi_rid_int[pt.IFU_BUS_TAG-1:0] = pt.BUILD_AHB_LITE ? ifu_axi_rid_ahb[pt.IFU_BUS_TAG-1:0] : ifu_axi_rid[pt.IFU_BUS_TAG-1:0]; assign ifu_axi_rdata_int[63:0] = pt.BUILD_AHB_LITE ? ifu_axi_rdata_ahb[63:0] : ifu_axi_rdata[63:0]; assign ifu_axi_rresp_int[1:0] = pt.BUILD_AHB_LITE ? ifu_axi_rresp_ahb[1:0] : ifu_axi_rresp[1:0]; assign ifu_axi_rlast_int = pt.BUILD_AHB_LITE ? ifu_axi_rlast_ahb : ifu_axi_rlast; assign sb_axi_awready_int = pt.BUILD_AHB_LITE ? sb_axi_awready_ahb : sb_axi_awready; assign sb_axi_wready_int = pt.BUILD_AHB_LITE ? sb_axi_wready_ahb : sb_axi_wready; assign sb_axi_bvalid_int = pt.BUILD_AHB_LITE ? sb_axi_bvalid_ahb : sb_axi_bvalid; assign sb_axi_bresp_int[1:0] = pt.BUILD_AHB_LITE ? sb_axi_bresp_ahb[1:0] : sb_axi_bresp[1:0]; assign sb_axi_bid_int[pt.SB_BUS_TAG-1:0] = pt.BUILD_AHB_LITE ? sb_axi_bid_ahb[pt.SB_BUS_TAG-1:0] : sb_axi_bid[pt.SB_BUS_TAG-1:0]; assign sb_axi_arready_int = pt.BUILD_AHB_LITE ? sb_axi_arready_ahb : sb_axi_arready; assign sb_axi_rvalid_int = pt.BUILD_AHB_LITE ? sb_axi_rvalid_ahb : sb_axi_rvalid; assign sb_axi_rid_int[pt.SB_BUS_TAG-1:0] = pt.BUILD_AHB_LITE ? sb_axi_rid_ahb[pt.SB_BUS_TAG-1:0] : sb_axi_rid[pt.SB_BUS_TAG-1:0]; assign sb_axi_rdata_int[63:0] = pt.BUILD_AHB_LITE ? sb_axi_rdata_ahb[63:0] : sb_axi_rdata[63:0]; assign sb_axi_rresp_int[1:0] = pt.BUILD_AHB_LITE ? sb_axi_rresp_ahb[1:0] : sb_axi_rresp[1:0]; assign sb_axi_rlast_int = pt.BUILD_AHB_LITE ? sb_axi_rlast_ahb : sb_axi_rlast; assign dma_axi_awvalid_int = pt.BUILD_AHB_LITE ? dma_axi_awvalid_ahb : dma_axi_awvalid; assign dma_axi_awid_int[pt.DMA_BUS_TAG-1:0] = pt.BUILD_AHB_LITE ? dma_axi_awid_ahb[pt.DMA_BUS_TAG-1:0] : dma_axi_awid[pt.DMA_BUS_TAG-1:0]; assign dma_axi_awaddr_int[31:0] = pt.BUILD_AHB_LITE ? dma_axi_awaddr_ahb[31:0] : dma_axi_awaddr[31:0]; assign dma_axi_awsize_int[2:0] = pt.BUILD_AHB_LITE ? dma_axi_awsize_ahb[2:0] : dma_axi_awsize[2:0]; assign dma_axi_awprot_int[2:0] = pt.BUILD_AHB_LITE ? dma_axi_awprot_ahb[2:0] : dma_axi_awprot[2:0]; assign dma_axi_awlen_int[7:0] = pt.BUILD_AHB_LITE ? dma_axi_awlen_ahb[7:0] : dma_axi_awlen[7:0]; assign dma_axi_awburst_int[1:0] = pt.BUILD_AHB_LITE ? dma_axi_awburst_ahb[1:0] : dma_axi_awburst[1:0]; assign dma_axi_wvalid_int = pt.BUILD_AHB_LITE ? dma_axi_wvalid_ahb : dma_axi_wvalid; assign dma_axi_wdata_int[63:0] = pt.BUILD_AHB_LITE ? dma_axi_wdata_ahb[63:0] : dma_axi_wdata; assign dma_axi_wstrb_int[7:0] = pt.BUILD_AHB_LITE ? dma_axi_wstrb_ahb[7:0] : dma_axi_wstrb[7:0]; assign dma_axi_wlast_int = pt.BUILD_AHB_LITE ? dma_axi_wlast_ahb : dma_axi_wlast; assign dma_axi_bready_int = pt.BUILD_AHB_LITE ? dma_axi_bready_ahb : dma_axi_bready; assign dma_axi_arvalid_int = pt.BUILD_AHB_LITE ? dma_axi_arvalid_ahb : dma_axi_arvalid; assign dma_axi_arid_int[pt.DMA_BUS_TAG-1:0] = pt.BUILD_AHB_LITE ? dma_axi_arid_ahb[pt.DMA_BUS_TAG-1:0] : dma_axi_arid[pt.DMA_BUS_TAG-1:0]; assign dma_axi_araddr_int[31:0] = pt.BUILD_AHB_LITE ? dma_axi_araddr_ahb[31:0] : dma_axi_araddr[31:0]; assign dma_axi_arsize_int[2:0] = pt.BUILD_AHB_LITE ? dma_axi_arsize_ahb[2:0] : dma_axi_arsize[2:0]; assign dma_axi_arprot_int[2:0] = pt.BUILD_AHB_LITE ? dma_axi_arprot_ahb[2:0] : dma_axi_arprot[2:0]; assign dma_axi_arlen_int[7:0] = pt.BUILD_AHB_LITE ? dma_axi_arlen_ahb[7:0] : dma_axi_arlen[7:0]; assign dma_axi_arburst_int[1:0] = pt.BUILD_AHB_LITE ? dma_axi_arburst_ahb[1:0] : dma_axi_arburst[1:0]; assign dma_axi_rready_int = pt.BUILD_AHB_LITE ? dma_axi_rready_ahb : dma_axi_rready; if (pt.BUILD_AHB_LITE == 1) begin `ifdef RV_ASSERT_ON property ahb_trxn_aligned; @(posedge clk) disable iff(~rst_l) (lsu_htrans[1:0] != 2'b0) |-> ((lsu_hsize[2:0] == 3'h0) | ((lsu_hsize[2:0] == 3'h1) & (lsu_haddr[0] == 1'b0)) | ((lsu_hsize[2:0] == 3'h2) & (lsu_haddr[1:0] == 2'b0)) | ((lsu_hsize[2:0] == 3'h3) & (lsu_haddr[2:0] == 3'b0))); endproperty assert_ahb_trxn_aligned: assert property (ahb_trxn_aligned) else $display("Assertion ahb_trxn_aligned failed: lsu_htrans=2'h%h, lsu_hsize=3'h%h, lsu_haddr=32'h%h",lsu_htrans[1:0], lsu_hsize[2:0], lsu_haddr[31:0]); property dma_trxn_aligned; @(posedge clk) disable iff(~rst_l) (dma_htrans[1:0] != 2'b0) |-> ((dma_hsize[2:0] == 3'h0) | ((dma_hsize[2:0] == 3'h1) & (dma_haddr[0] == 1'b0)) | ((dma_hsize[2:0] == 3'h2) & (dma_haddr[1:0] == 2'b0)) | ((dma_hsize[2:0] == 3'h3) & (dma_haddr[2:0] == 3'b0))); endproperty `endif end // if (pt.BUILD_AHB_LITE == 1) // unpack packet // also need retires_p==3 assign trace_rv_i_insn_ip[31:0] = trace_rv_trace_pkt.trace_rv_i_insn_ip[31:0]; assign trace_rv_i_address_ip[31:0] = trace_rv_trace_pkt.trace_rv_i_address_ip[31:0]; assign trace_rv_i_valid_ip = trace_rv_trace_pkt.trace_rv_i_valid_ip; assign trace_rv_i_exception_ip = trace_rv_trace_pkt.trace_rv_i_exception_ip; assign trace_rv_i_ecause_ip[4:0] = trace_rv_trace_pkt.trace_rv_i_ecause_ip[4:0]; assign trace_rv_i_interrupt_ip = trace_rv_trace_pkt.trace_rv_i_interrupt_ip; assign trace_rv_i_tval_ip[31:0] = trace_rv_trace_pkt.trace_rv_i_tval_ip[31:0]; endmodule // el2_veer ================================================ FILE: design/el2_veer_lockstep.sv ================================================ // Copyright 2024 Antmicro // // SPDX-License-Identifier: Apache-2.0 module el2_veer_lockstep import el2_pkg::*; #( `include "el2_param.vh" ) ( `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_regfile_if.veer_rf_sink main_core_regfile, `endif input logic clk, input logic rst_l, input logic dbg_rst_l, input logic [31:1] rst_vec, input logic nmi_int, input logic [31:1] nmi_vec, input logic core_rst_l, // This is "rst_l | dbg_rst_l" input logic active_l2clk, input logic free_l2clk, input logic [31:0] trace_rv_i_insn_ip, input logic [31:0] trace_rv_i_address_ip, input logic trace_rv_i_valid_ip, input logic trace_rv_i_exception_ip, input logic [4:0] trace_rv_i_ecause_ip, input logic trace_rv_i_interrupt_ip, input logic [31:0] trace_rv_i_tval_ip, input logic dccm_clk_override, input logic icm_clk_override, input logic dec_tlu_core_ecc_disable, // external halt/run interface input logic i_cpu_halt_req, // Asynchronous Halt request to CPU input logic i_cpu_run_req, // Asynchronous Restart request to CPU input logic o_cpu_halt_ack, // Core Acknowledge to Halt request input logic o_cpu_halt_status, // 1'b1 indicates processor is halted input logic o_cpu_run_ack, // Core Acknowledge to run request input logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request input logic [31:4] core_id, // CORE ID // external MPC halt/run interface input logic mpc_debug_halt_req, // Async halt request input logic mpc_debug_run_req, // Async run request input logic mpc_reset_run_req, // Run/halt after reset input logic mpc_debug_halt_ack, // Halt ack input logic mpc_debug_run_ack, // Run ack input logic debug_brkpt_status, // debug breakpoint input logic dec_tlu_perfcnt0, // toggles when slot0 perf counter 0 has an event inc input logic dec_tlu_perfcnt1, input logic dec_tlu_perfcnt2, input logic dec_tlu_perfcnt3, // DCCM ports input logic dccm_wren, input logic dccm_rden, input logic [ pt.DCCM_BITS-1:0] dccm_wr_addr_lo, input logic [ pt.DCCM_BITS-1:0] dccm_wr_addr_hi, input logic [ pt.DCCM_BITS-1:0] dccm_rd_addr_lo, input logic [ pt.DCCM_BITS-1:0] dccm_rd_addr_hi, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // ICCM ports input logic [pt.ICCM_BITS-1:1] iccm_rw_addr, input logic iccm_wren, input logic iccm_rden, input logic [ 2:0] iccm_wr_size, input logic [ 77:0] iccm_wr_data, input logic iccm_buf_correct_ecc, input logic iccm_correction_state, input logic [63:0] iccm_rd_data, input logic [77:0] iccm_rd_data_ecc, // ICache , ITAG ports input logic [ 31:1] ic_rw_addr, input logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid, input logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en, input logic ic_rd_en, input logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC input logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [25:0] ictag_debug_rd_data, // Debug icache tag. input logic [70:0] ic_debug_wr_data, // Debug wr cache. input logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, input logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, input logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache. input logic ic_sel_premux_data, // Select premux data input logic [ pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. input logic ic_debug_rd_en, // Icache debug rd input logic ic_debug_wr_en, // Icache debug wr input logic ic_debug_tag_array, // Debug tag array input logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. input logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, input logic ic_tag_perr, // Icache Tag parity error //-------------------------- LSU AXI signals-------------------------- // AXI Write Channels input logic lsu_axi_awvalid, input logic lsu_axi_awready, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid, input logic [ 31:0] lsu_axi_awaddr, input logic [ 3:0] lsu_axi_awregion, input logic [ 7:0] lsu_axi_awlen, input logic [ 2:0] lsu_axi_awsize, input logic [ 1:0] lsu_axi_awburst, input logic lsu_axi_awlock, input logic [ 3:0] lsu_axi_awcache, input logic [ 2:0] lsu_axi_awprot, input logic [ 3:0] lsu_axi_awqos, input logic lsu_axi_wvalid, input logic lsu_axi_wready, input logic [63:0] lsu_axi_wdata, input logic [ 7:0] lsu_axi_wstrb, input logic lsu_axi_wlast, input logic lsu_axi_bvalid, input logic lsu_axi_bready, input logic [ 1:0] lsu_axi_bresp, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid, // AXI Read Channels input logic lsu_axi_arvalid, input logic lsu_axi_arready, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid, input logic [ 31:0] lsu_axi_araddr, input logic [ 3:0] lsu_axi_arregion, input logic [ 7:0] lsu_axi_arlen, input logic [ 2:0] lsu_axi_arsize, input logic [ 1:0] lsu_axi_arburst, input logic lsu_axi_arlock, input logic [ 3:0] lsu_axi_arcache, input logic [ 2:0] lsu_axi_arprot, input logic [ 3:0] lsu_axi_arqos, input logic lsu_axi_rvalid, input logic lsu_axi_rready, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid, input logic [ 63:0] lsu_axi_rdata, input logic [ 1:0] lsu_axi_rresp, input logic lsu_axi_rlast, //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels input logic ifu_axi_awvalid, input logic ifu_axi_awready, input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid, input logic [ 31:0] ifu_axi_awaddr, input logic [ 3:0] ifu_axi_awregion, input logic [ 7:0] ifu_axi_awlen, input logic [ 2:0] ifu_axi_awsize, input logic [ 1:0] ifu_axi_awburst, input logic ifu_axi_awlock, input logic [ 3:0] ifu_axi_awcache, input logic [ 2:0] ifu_axi_awprot, input logic [ 3:0] ifu_axi_awqos, input logic ifu_axi_wvalid, input logic ifu_axi_wready, input logic [63:0] ifu_axi_wdata, input logic [ 7:0] ifu_axi_wstrb, input logic ifu_axi_wlast, input logic ifu_axi_bvalid, input logic ifu_axi_bready, input logic [ 1:0] ifu_axi_bresp, input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_bid, // AXI Read Channels input logic ifu_axi_arvalid, input logic ifu_axi_arready, input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid, input logic [ 31:0] ifu_axi_araddr, input logic [ 3:0] ifu_axi_arregion, input logic [ 7:0] ifu_axi_arlen, input logic [ 2:0] ifu_axi_arsize, input logic [ 1:0] ifu_axi_arburst, input logic ifu_axi_arlock, input logic [ 3:0] ifu_axi_arcache, input logic [ 2:0] ifu_axi_arprot, input logic [ 3:0] ifu_axi_arqos, input logic ifu_axi_rvalid, input logic ifu_axi_rready, input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid, input logic [ 63:0] ifu_axi_rdata, input logic [ 1:0] ifu_axi_rresp, input logic ifu_axi_rlast, //-------------------------- SB AXI signals-------------------------- // AXI Write Channels input logic sb_axi_awvalid, input logic sb_axi_awready, input logic [pt.SB_BUS_TAG-1:0] sb_axi_awid, input logic [ 31:0] sb_axi_awaddr, input logic [ 3:0] sb_axi_awregion, input logic [ 7:0] sb_axi_awlen, input logic [ 2:0] sb_axi_awsize, input logic [ 1:0] sb_axi_awburst, input logic sb_axi_awlock, input logic [ 3:0] sb_axi_awcache, input logic [ 2:0] sb_axi_awprot, input logic [ 3:0] sb_axi_awqos, input logic sb_axi_wvalid, input logic sb_axi_wready, input logic [63:0] sb_axi_wdata, input logic [ 7:0] sb_axi_wstrb, input logic sb_axi_wlast, input logic sb_axi_bvalid, input logic sb_axi_bready, input logic [ 1:0] sb_axi_bresp, input logic [pt.SB_BUS_TAG-1:0] sb_axi_bid, // AXI Read Channels input logic sb_axi_arvalid, input logic sb_axi_arready, input logic [pt.SB_BUS_TAG-1:0] sb_axi_arid, input logic [ 31:0] sb_axi_araddr, input logic [ 3:0] sb_axi_arregion, input logic [ 7:0] sb_axi_arlen, input logic [ 2:0] sb_axi_arsize, input logic [ 1:0] sb_axi_arburst, input logic sb_axi_arlock, input logic [ 3:0] sb_axi_arcache, input logic [ 2:0] sb_axi_arprot, input logic [ 3:0] sb_axi_arqos, input logic sb_axi_rvalid, input logic sb_axi_rready, input logic [pt.SB_BUS_TAG-1:0] sb_axi_rid, input logic [ 63:0] sb_axi_rdata, input logic [ 1:0] sb_axi_rresp, input logic sb_axi_rlast, //-------------------------- DMA AXI signals-------------------------- // AXI Write Channels input logic dma_axi_awvalid, input logic dma_axi_awready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid, input logic [ 31:0] dma_axi_awaddr, input logic [ 2:0] dma_axi_awsize, input logic [ 2:0] dma_axi_awprot, input logic [ 7:0] dma_axi_awlen, input logic [ 1:0] dma_axi_awburst, input logic dma_axi_wvalid, input logic dma_axi_wready, input logic [63:0] dma_axi_wdata, input logic [ 7:0] dma_axi_wstrb, input logic dma_axi_wlast, input logic dma_axi_bvalid, input logic dma_axi_bready, input logic [ 1:0] dma_axi_bresp, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_bid, // AXI Read Channels input logic dma_axi_arvalid, input logic dma_axi_arready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid, input logic [ 31:0] dma_axi_araddr, input logic [ 2:0] dma_axi_arsize, input logic [ 2:0] dma_axi_arprot, input logic [ 7:0] dma_axi_arlen, input logic [ 1:0] dma_axi_arburst, input logic dma_axi_rvalid, input logic dma_axi_rready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_rid, input logic [ 63:0] dma_axi_rdata, input logic [ 1:0] dma_axi_rresp, input logic dma_axi_rlast, //// AHB LITE BUS input logic [31:0] haddr, input logic [ 2:0] hburst, input logic hmastlock, input logic [ 3:0] hprot, input logic [ 2:0] hsize, input logic [ 1:0] htrans, input logic hwrite, input logic [63:0] hrdata, input logic hready, input logic hresp, // LSU AHB Master input logic [31:0] lsu_haddr, input logic [ 2:0] lsu_hburst, input logic lsu_hmastlock, input logic [ 3:0] lsu_hprot, input logic [ 2:0] lsu_hsize, input logic [ 1:0] lsu_htrans, input logic lsu_hwrite, input logic [63:0] lsu_hwdata, input logic [63:0] lsu_hrdata, input logic lsu_hready, input logic lsu_hresp, //System Bus Debug Master input logic [31:0] sb_haddr, input logic [ 2:0] sb_hburst, input logic sb_hmastlock, input logic [ 3:0] sb_hprot, input logic [ 2:0] sb_hsize, input logic [ 1:0] sb_htrans, input logic sb_hwrite, input logic [63:0] sb_hwdata, input logic [63:0] sb_hrdata, input logic sb_hready, input logic sb_hresp, // DMA Slave input logic dma_hsel, input logic [31:0] dma_haddr, input logic [ 2:0] dma_hburst, input logic dma_hmastlock, input logic [ 3:0] dma_hprot, input logic [ 2:0] dma_hsize, input logic [ 1:0] dma_htrans, input logic dma_hwrite, input logic [63:0] dma_hwdata, input logic dma_hreadyin, input logic [63:0] dma_hrdata, input logic dma_hreadyout, input logic dma_hresp, input logic lsu_bus_clk_en, input logic ifu_bus_clk_en, input logic dbg_bus_clk_en, input logic dma_bus_clk_en, input logic dmi_reg_en, // read or write input logic [ 6:0] dmi_reg_addr, // address of DM register input logic dmi_reg_wr_en, // write instruction input logic [31:0] dmi_reg_wdata, // write data input logic [31:0] dmi_reg_rdata, // ICCM/DCCM ECC status input logic iccm_ecc_single_error, input logic iccm_ecc_double_error, input logic dccm_ecc_single_error, input logic dccm_ecc_double_error, input logic [pt.PIC_TOTAL_INT:1] extintsrc_req, input logic timer_int, input logic soft_int, input logic scan_mode, // Shadow Core control input logic disable_corruption_detection_i, input logic lockstep_err_injection_en_i, // Equivalency Checker output output logic corruption_detected_o ); localparam int unsigned LockstepDelay = pt.LOCKSTEP_DELAY; // Delay I/O; in clock cycles // Outputs typedef struct packed { logic core_rst_l; logic [31:0] trace_rv_i_insn_ip; logic [31:0] trace_rv_i_address_ip; logic trace_rv_i_valid_ip; logic trace_rv_i_exception_ip; logic [4:0] trace_rv_i_ecause_ip; logic trace_rv_i_interrupt_ip; logic [31:0] trace_rv_i_tval_ip; logic dccm_clk_override; logic icm_clk_override; logic dec_tlu_core_ecc_disable; logic o_cpu_halt_ack; logic o_cpu_halt_status; logic o_cpu_run_ack; logic o_debug_mode_status; logic mpc_debug_halt_ack; logic mpc_debug_run_ack; logic debug_brkpt_status; logic dec_tlu_perfcnt0; logic dec_tlu_perfcnt1; logic dec_tlu_perfcnt2; logic dec_tlu_perfcnt3; logic dccm_wren; logic dccm_rden; logic [pt.DCCM_BITS-1:0] dccm_wr_addr_lo; logic [pt.DCCM_BITS-1:0] dccm_wr_addr_hi; logic [pt.DCCM_BITS-1:0] dccm_rd_addr_lo; logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi; logic [pt.ICCM_BITS-1:1] iccm_rw_addr; logic iccm_wren; logic iccm_rden; logic [2:0] iccm_wr_size; logic [77:0] iccm_wr_data; logic iccm_buf_correct_ecc; logic iccm_correction_state; logic [31:1] ic_rw_addr; logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid; logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en; logic ic_rd_en; logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data; logic [70:0] ic_debug_wr_data; logic [63:0] ic_premux_data; logic ic_sel_premux_data; logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr; logic ic_debug_rd_en; logic ic_debug_wr_en; logic ic_debug_tag_array; logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way; logic lsu_axi_awvalid; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid; logic [31:0] lsu_axi_awaddr; logic [3:0] lsu_axi_awregion; logic [7:0] lsu_axi_awlen; logic [2:0] lsu_axi_awsize; logic [1:0] lsu_axi_awburst; logic lsu_axi_awlock; logic [3:0] lsu_axi_awcache; logic [2:0] lsu_axi_awprot; logic [3:0] lsu_axi_awqos; logic lsu_axi_wvalid; logic [63:0] lsu_axi_wdata; logic [7:0] lsu_axi_wstrb; logic lsu_axi_wlast; logic lsu_axi_bready; logic lsu_axi_arvalid; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid; logic [31:0] lsu_axi_araddr; logic [3:0] lsu_axi_arregion; logic [7:0] lsu_axi_arlen; logic [2:0] lsu_axi_arsize; logic [1:0] lsu_axi_arburst; logic lsu_axi_arlock; logic [3:0] lsu_axi_arcache; logic [2:0] lsu_axi_arprot; logic [3:0] lsu_axi_arqos; logic lsu_axi_rready; logic ifu_axi_awvalid; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid; logic [31:0] ifu_axi_awaddr; logic [3:0] ifu_axi_awregion; logic [7:0] ifu_axi_awlen; logic [2:0] ifu_axi_awsize; logic [1:0] ifu_axi_awburst; logic ifu_axi_awlock; logic [3:0] ifu_axi_awcache; logic [2:0] ifu_axi_awprot; logic [3:0] ifu_axi_awqos; logic ifu_axi_wvalid; logic [63:0] ifu_axi_wdata; logic [7:0] ifu_axi_wstrb; logic ifu_axi_wlast; logic ifu_axi_bready; logic ifu_axi_arvalid; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid; logic [31:0] ifu_axi_araddr; logic [3:0] ifu_axi_arregion; logic [7:0] ifu_axi_arlen; logic [2:0] ifu_axi_arsize; logic [1:0] ifu_axi_arburst; logic ifu_axi_arlock; logic [3:0] ifu_axi_arcache; logic [2:0] ifu_axi_arprot; logic [3:0] ifu_axi_arqos; logic ifu_axi_rready; logic sb_axi_awvalid; logic [pt.SB_BUS_TAG-1:0] sb_axi_awid; logic [31:0] sb_axi_awaddr; logic [3:0] sb_axi_awregion; logic [7:0] sb_axi_awlen; logic [2:0] sb_axi_awsize; logic [1:0] sb_axi_awburst; logic sb_axi_awlock; logic [3:0] sb_axi_awcache; logic [2:0] sb_axi_awprot; logic [3:0] sb_axi_awqos; logic sb_axi_wvalid; logic [63:0] sb_axi_wdata; logic [7:0] sb_axi_wstrb; logic sb_axi_wlast; logic sb_axi_bready; logic sb_axi_arvalid; logic [pt.SB_BUS_TAG-1:0] sb_axi_arid; logic [31:0] sb_axi_araddr; logic [3:0] sb_axi_arregion; logic [7:0] sb_axi_arlen; logic [2:0] sb_axi_arsize; logic [1:0] sb_axi_arburst; logic sb_axi_arlock; logic [3:0] sb_axi_arcache; logic [2:0] sb_axi_arprot; logic [3:0] sb_axi_arqos; logic sb_axi_rready; logic dma_axi_awready; logic dma_axi_wready; logic dma_axi_bvalid; logic [1:0] dma_axi_bresp; logic [pt.DMA_BUS_TAG-1:0] dma_axi_bid; logic dma_axi_arready; logic dma_axi_rvalid; logic [pt.DMA_BUS_TAG-1:0] dma_axi_rid; logic [63:0] dma_axi_rdata; logic [1:0] dma_axi_rresp; logic dma_axi_rlast; logic [31:0] haddr; logic [2:0] hburst; logic hmastlock; logic [3:0] hprot; logic [2:0] hsize; logic [1:0] htrans; logic hwrite; logic [31:0] lsu_haddr; logic [2:0] lsu_hburst; logic lsu_hmastlock; logic [3:0] lsu_hprot; logic [2:0] lsu_hsize; logic [1:0] lsu_htrans; logic lsu_hwrite; logic [63:0] lsu_hwdata; logic [31:0] sb_haddr; logic [2:0] sb_hburst; logic sb_hmastlock; logic [3:0] sb_hprot; logic [2:0] sb_hsize; logic [1:0] sb_htrans; logic sb_hwrite; logic [63:0] sb_hwdata; logic [63:0] dma_hrdata; logic dma_hreadyout; logic dma_hresp; logic [31:0] dmi_reg_rdata; logic iccm_ecc_single_error; logic iccm_ecc_double_error; logic dccm_ecc_single_error; logic dccm_ecc_double_error; } veer_outputs_t; // Inputs typedef struct packed { logic [31:1] rst_vec; logic nmi_int; logic [31:1] nmi_vec; logic i_cpu_halt_req; logic i_cpu_run_req; logic [31:4] core_id; logic mpc_debug_halt_req; logic mpc_debug_run_req; logic mpc_reset_run_req; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi; logic [63:0] iccm_rd_data; logic [77:0] iccm_rd_data_ecc; logic [63:0] ic_rd_data; logic [70:0] ic_debug_rd_data; logic [25:0] ictag_debug_rd_data; logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr; logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr; logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit; logic ic_tag_perr; logic lsu_axi_awready; logic lsu_axi_wready; logic lsu_axi_bvalid; logic [1:0] lsu_axi_bresp; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid; logic lsu_axi_arready; logic lsu_axi_rvalid; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid; logic [63:0] lsu_axi_rdata; logic [1:0] lsu_axi_rresp; logic lsu_axi_rlast; logic ifu_axi_awready; logic ifu_axi_wready; logic ifu_axi_bvalid; logic [1:0] ifu_axi_bresp; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_bid; logic ifu_axi_arready; logic ifu_axi_rvalid; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid; logic [63:0] ifu_axi_rdata; logic [1:0] ifu_axi_rresp; logic ifu_axi_rlast; logic sb_axi_awready; logic sb_axi_wready; logic sb_axi_bvalid; logic [1:0] sb_axi_bresp; logic [pt.SB_BUS_TAG-1:0] sb_axi_bid; logic sb_axi_arready; logic sb_axi_rvalid; logic [pt.SB_BUS_TAG-1:0] sb_axi_rid; logic [63:0] sb_axi_rdata; logic [1:0] sb_axi_rresp; logic sb_axi_rlast; logic dma_axi_awvalid; logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid; logic [31:0] dma_axi_awaddr; logic [2:0] dma_axi_awsize; logic [2:0] dma_axi_awprot; logic [7:0] dma_axi_awlen; logic [1:0] dma_axi_awburst; logic dma_axi_wvalid; logic [63:0] dma_axi_wdata; logic [7:0] dma_axi_wstrb; logic dma_axi_wlast; logic dma_axi_bready; logic dma_axi_arvalid; logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid; logic [31:0] dma_axi_araddr; logic [2:0] dma_axi_arsize; logic [2:0] dma_axi_arprot; logic [7:0] dma_axi_arlen; logic [1:0] dma_axi_arburst; logic dma_axi_rready; logic [63:0] hrdata; logic hready; logic hresp; logic [63:0] lsu_hrdata; logic lsu_hready; logic lsu_hresp; logic [63:0] sb_hrdata; logic sb_hready; logic sb_hresp; logic dma_hsel; logic [31:0] dma_haddr; logic [2:0] dma_hburst; logic dma_hmastlock; logic [3:0] dma_hprot; logic [2:0] dma_hsize; logic [1:0] dma_htrans; logic dma_hwrite; logic [63:0] dma_hwdata; logic dma_hreadyin; logic lsu_bus_clk_en; logic ifu_bus_clk_en; logic dbg_bus_clk_en; logic dma_bus_clk_en; logic dmi_reg_en; logic [6:0] dmi_reg_addr; logic dmi_reg_wr_en; logic [31:0] dmi_reg_wdata; logic [pt.PIC_TOTAL_INT:1] extintsrc_req; logic timer_int; logic soft_int; logic scan_mode; } veer_inputs_t; veer_inputs_t main_core_inputs; veer_inputs_t [LockstepDelay:0] delay_input_d; veer_inputs_t shadow_core_inputs; veer_outputs_t main_core_outputs; veer_outputs_t [LockstepDelay:0] delay_output_d; veer_outputs_t delayed_main_core_outputs; veer_outputs_t shadow_core_outputs; assign shadow_core_inputs = delay_input_d[LockstepDelay]; assign delayed_main_core_outputs = delay_output_d[LockstepDelay]; // Capture input assign main_core_inputs.rst_vec = rst_vec; assign main_core_inputs.nmi_int = nmi_int; assign main_core_inputs.nmi_vec = nmi_vec; assign main_core_inputs.i_cpu_halt_req = i_cpu_halt_req; assign main_core_inputs.i_cpu_run_req = i_cpu_run_req; assign main_core_inputs.core_id = core_id; assign main_core_inputs.mpc_debug_halt_req = mpc_debug_halt_req; assign main_core_inputs.mpc_debug_run_req = mpc_debug_run_req; assign main_core_inputs.mpc_reset_run_req = mpc_reset_run_req; assign main_core_inputs.dccm_rd_data_lo = dccm_rd_data_lo; assign main_core_inputs.dccm_rd_data_hi = dccm_rd_data_hi; assign main_core_inputs.iccm_rd_data = iccm_rd_data; assign main_core_inputs.iccm_rd_data_ecc = iccm_rd_data_ecc; assign main_core_inputs.ic_rd_data = ic_rd_data; assign main_core_inputs.ic_debug_rd_data = ic_debug_rd_data; assign main_core_inputs.ictag_debug_rd_data = ictag_debug_rd_data; assign main_core_inputs.ic_eccerr = ic_eccerr; assign main_core_inputs.ic_parerr = ic_parerr; assign main_core_inputs.ic_rd_hit = ic_rd_hit; assign main_core_inputs.ic_tag_perr = ic_tag_perr; assign main_core_inputs.lsu_axi_awready = lsu_axi_awready; assign main_core_inputs.lsu_axi_wready = lsu_axi_wready; assign main_core_inputs.lsu_axi_bvalid = lsu_axi_bvalid; assign main_core_inputs.lsu_axi_bresp = lsu_axi_bresp; assign main_core_inputs.lsu_axi_bid = lsu_axi_bid; assign main_core_inputs.lsu_axi_arready = lsu_axi_arready; assign main_core_inputs.lsu_axi_rvalid = lsu_axi_rvalid; assign main_core_inputs.lsu_axi_rid = lsu_axi_rid; assign main_core_inputs.lsu_axi_rdata = lsu_axi_rdata; assign main_core_inputs.lsu_axi_rresp = lsu_axi_rresp; assign main_core_inputs.lsu_axi_rlast = lsu_axi_rlast; assign main_core_inputs.ifu_axi_awready = ifu_axi_awready; assign main_core_inputs.ifu_axi_wready = ifu_axi_wready; assign main_core_inputs.ifu_axi_bvalid = ifu_axi_bvalid; assign main_core_inputs.ifu_axi_bresp = ifu_axi_bresp; assign main_core_inputs.ifu_axi_bid = ifu_axi_bid; assign main_core_inputs.ifu_axi_arready = ifu_axi_arready; assign main_core_inputs.ifu_axi_rvalid = ifu_axi_rvalid; assign main_core_inputs.ifu_axi_rid = ifu_axi_rid; assign main_core_inputs.ifu_axi_rdata = ifu_axi_rdata; assign main_core_inputs.ifu_axi_rresp = ifu_axi_rresp; assign main_core_inputs.ifu_axi_rlast = ifu_axi_rlast; assign main_core_inputs.sb_axi_awready = sb_axi_awready; assign main_core_inputs.sb_axi_wready = sb_axi_wready; assign main_core_inputs.sb_axi_bvalid = sb_axi_bvalid; assign main_core_inputs.sb_axi_bresp = sb_axi_bresp; assign main_core_inputs.sb_axi_bid = sb_axi_bid; assign main_core_inputs.sb_axi_arready = sb_axi_arready; assign main_core_inputs.sb_axi_rvalid = sb_axi_rvalid; assign main_core_inputs.sb_axi_rid = sb_axi_rid; assign main_core_inputs.sb_axi_rdata = sb_axi_rdata; assign main_core_inputs.sb_axi_rresp = sb_axi_rresp; assign main_core_inputs.sb_axi_rlast = sb_axi_rlast; assign main_core_inputs.dma_axi_awvalid = dma_axi_awvalid; assign main_core_inputs.dma_axi_awid = dma_axi_awid; assign main_core_inputs.dma_axi_awaddr = dma_axi_awaddr; assign main_core_inputs.dma_axi_awsize = dma_axi_awsize; assign main_core_inputs.dma_axi_awprot = dma_axi_awprot; assign main_core_inputs.dma_axi_awlen = dma_axi_awlen; assign main_core_inputs.dma_axi_awburst = dma_axi_awburst; assign main_core_inputs.dma_axi_wvalid = dma_axi_wvalid; assign main_core_inputs.dma_axi_wdata = dma_axi_wdata; assign main_core_inputs.dma_axi_wstrb = dma_axi_wstrb; assign main_core_inputs.dma_axi_wlast = dma_axi_wlast; assign main_core_inputs.dma_axi_bready = dma_axi_bready; assign main_core_inputs.dma_axi_arvalid = dma_axi_arvalid; assign main_core_inputs.dma_axi_arid = dma_axi_arid; assign main_core_inputs.dma_axi_araddr = dma_axi_araddr; assign main_core_inputs.dma_axi_arsize = dma_axi_arsize; assign main_core_inputs.dma_axi_arprot = dma_axi_arprot; assign main_core_inputs.dma_axi_arlen = dma_axi_arlen; assign main_core_inputs.dma_axi_arburst = dma_axi_arburst; assign main_core_inputs.dma_axi_rready = dma_axi_rready; assign main_core_inputs.hrdata = hrdata; assign main_core_inputs.hready = hready; assign main_core_inputs.hresp = hresp; assign main_core_inputs.lsu_hrdata = lsu_hrdata; assign main_core_inputs.lsu_hready = lsu_hready; assign main_core_inputs.lsu_hresp = lsu_hresp; assign main_core_inputs.sb_hrdata = sb_hrdata; assign main_core_inputs.sb_hready = sb_hready; assign main_core_inputs.sb_hresp = sb_hresp; assign main_core_inputs.dma_hsel = dma_hsel; assign main_core_inputs.dma_haddr = dma_haddr; assign main_core_inputs.dma_hburst = dma_hburst; assign main_core_inputs.dma_hmastlock = dma_hmastlock; assign main_core_inputs.dma_hprot = dma_hprot; assign main_core_inputs.dma_hsize = dma_hsize; assign main_core_inputs.dma_htrans = dma_htrans; assign main_core_inputs.dma_hwrite = dma_hwrite; assign main_core_inputs.dma_hwdata = dma_hwdata; assign main_core_inputs.dma_hreadyin = dma_hreadyin; assign main_core_inputs.lsu_bus_clk_en = lsu_bus_clk_en; assign main_core_inputs.ifu_bus_clk_en = ifu_bus_clk_en; assign main_core_inputs.dbg_bus_clk_en = dbg_bus_clk_en; assign main_core_inputs.dma_bus_clk_en = dma_bus_clk_en; assign main_core_inputs.dmi_reg_en = dmi_reg_en; assign main_core_inputs.dmi_reg_addr = dmi_reg_addr; assign main_core_inputs.dmi_reg_wr_en = dmi_reg_wr_en; assign main_core_inputs.dmi_reg_wdata = dmi_reg_wdata; assign main_core_inputs.extintsrc_req = extintsrc_req; assign main_core_inputs.timer_int = timer_int; assign main_core_inputs.soft_int = soft_int; assign main_core_inputs.scan_mode = scan_mode; // Capture output assign main_core_outputs.core_rst_l = core_rst_l; assign main_core_outputs.trace_rv_i_insn_ip = trace_rv_i_insn_ip; assign main_core_outputs.trace_rv_i_address_ip = trace_rv_i_address_ip; assign main_core_outputs.trace_rv_i_valid_ip = trace_rv_i_valid_ip; assign main_core_outputs.trace_rv_i_exception_ip = trace_rv_i_exception_ip; assign main_core_outputs.trace_rv_i_ecause_ip = trace_rv_i_ecause_ip; assign main_core_outputs.trace_rv_i_interrupt_ip = trace_rv_i_interrupt_ip; assign main_core_outputs.trace_rv_i_tval_ip = trace_rv_i_tval_ip; assign main_core_outputs.dccm_clk_override = dccm_clk_override; assign main_core_outputs.icm_clk_override = icm_clk_override; assign main_core_outputs.dec_tlu_core_ecc_disable = dec_tlu_core_ecc_disable; assign main_core_outputs.o_cpu_halt_ack = o_cpu_halt_ack; assign main_core_outputs.o_cpu_halt_status = o_cpu_halt_status; assign main_core_outputs.o_cpu_run_ack = o_cpu_run_ack; assign main_core_outputs.o_debug_mode_status = o_debug_mode_status; assign main_core_outputs.mpc_debug_halt_ack = mpc_debug_halt_ack; assign main_core_outputs.mpc_debug_run_ack = mpc_debug_run_ack; assign main_core_outputs.debug_brkpt_status = debug_brkpt_status; assign main_core_outputs.dec_tlu_perfcnt0 = dec_tlu_perfcnt0; assign main_core_outputs.dec_tlu_perfcnt1 = dec_tlu_perfcnt1; assign main_core_outputs.dec_tlu_perfcnt2 = dec_tlu_perfcnt2; assign main_core_outputs.dec_tlu_perfcnt3 = dec_tlu_perfcnt3; assign main_core_outputs.dccm_wren = dccm_wren; assign main_core_outputs.dccm_rden = dccm_rden; assign main_core_outputs.dccm_wr_addr_lo = dccm_wr_addr_lo; assign main_core_outputs.dccm_wr_addr_hi = dccm_wr_addr_hi; assign main_core_outputs.dccm_rd_addr_lo = dccm_rd_addr_lo; assign main_core_outputs.dccm_rd_addr_hi = dccm_rd_addr_hi; assign main_core_outputs.dccm_wr_data_lo = dccm_wr_data_lo; assign main_core_outputs.dccm_wr_data_hi = dccm_wr_data_hi; assign main_core_outputs.iccm_rw_addr = iccm_rw_addr; assign main_core_outputs.iccm_wren = iccm_wren; assign main_core_outputs.iccm_rden = iccm_rden; assign main_core_outputs.iccm_wr_size = iccm_wr_size; assign main_core_outputs.iccm_wr_data = iccm_wr_data; assign main_core_outputs.iccm_buf_correct_ecc = iccm_buf_correct_ecc; assign main_core_outputs.iccm_correction_state = iccm_correction_state; assign main_core_outputs.ic_rw_addr = ic_rw_addr; assign main_core_outputs.ic_tag_valid = ic_tag_valid; assign main_core_outputs.ic_wr_en = ic_wr_en; assign main_core_outputs.ic_rd_en = ic_rd_en; assign main_core_outputs.ic_wr_data = ic_wr_data; assign main_core_outputs.ic_debug_wr_data = ic_debug_wr_data; assign main_core_outputs.ic_premux_data = ic_premux_data; assign main_core_outputs.ic_sel_premux_data = ic_sel_premux_data; assign main_core_outputs.ic_debug_addr = ic_debug_addr; assign main_core_outputs.ic_debug_rd_en = ic_debug_rd_en; assign main_core_outputs.ic_debug_wr_en = ic_debug_wr_en; assign main_core_outputs.ic_debug_tag_array = ic_debug_tag_array; assign main_core_outputs.ic_debug_way = ic_debug_way; assign main_core_outputs.lsu_axi_awvalid = lsu_axi_awvalid; assign main_core_outputs.lsu_axi_awid = lsu_axi_awid; assign main_core_outputs.lsu_axi_awaddr = lsu_axi_awaddr; assign main_core_outputs.lsu_axi_awregion = lsu_axi_awregion; assign main_core_outputs.lsu_axi_awlen = lsu_axi_awlen; assign main_core_outputs.lsu_axi_awsize = lsu_axi_awsize; assign main_core_outputs.lsu_axi_awburst = lsu_axi_awburst; assign main_core_outputs.lsu_axi_awlock = lsu_axi_awlock; assign main_core_outputs.lsu_axi_awcache = lsu_axi_awcache; assign main_core_outputs.lsu_axi_awprot = lsu_axi_awprot; assign main_core_outputs.lsu_axi_awqos = lsu_axi_awqos; assign main_core_outputs.lsu_axi_wvalid = lsu_axi_wvalid; assign main_core_outputs.lsu_axi_wdata = lsu_axi_wdata; assign main_core_outputs.lsu_axi_wstrb = lsu_axi_wstrb; assign main_core_outputs.lsu_axi_wlast = lsu_axi_wlast; assign main_core_outputs.lsu_axi_bready = lsu_axi_bready; assign main_core_outputs.lsu_axi_arvalid = lsu_axi_arvalid; assign main_core_outputs.lsu_axi_arid = lsu_axi_arid; assign main_core_outputs.lsu_axi_araddr = lsu_axi_araddr; assign main_core_outputs.lsu_axi_arregion = lsu_axi_arregion; assign main_core_outputs.lsu_axi_arlen = lsu_axi_arlen; assign main_core_outputs.lsu_axi_arsize = lsu_axi_arsize; assign main_core_outputs.lsu_axi_arburst = lsu_axi_arburst; assign main_core_outputs.lsu_axi_arlock = lsu_axi_arlock; assign main_core_outputs.lsu_axi_arcache = lsu_axi_arcache; assign main_core_outputs.lsu_axi_arprot = lsu_axi_arprot; assign main_core_outputs.lsu_axi_arqos = lsu_axi_arqos; assign main_core_outputs.lsu_axi_rready = lsu_axi_rready; assign main_core_outputs.ifu_axi_awvalid = ifu_axi_awvalid; assign main_core_outputs.ifu_axi_awid = ifu_axi_awid; assign main_core_outputs.ifu_axi_awaddr = ifu_axi_awaddr; assign main_core_outputs.ifu_axi_awregion = ifu_axi_awregion; assign main_core_outputs.ifu_axi_awlen = ifu_axi_awlen; assign main_core_outputs.ifu_axi_awsize = ifu_axi_awsize; assign main_core_outputs.ifu_axi_awburst = ifu_axi_awburst; assign main_core_outputs.ifu_axi_awlock = ifu_axi_awlock; assign main_core_outputs.ifu_axi_awcache = ifu_axi_awcache; assign main_core_outputs.ifu_axi_awprot = ifu_axi_awprot; assign main_core_outputs.ifu_axi_awqos = ifu_axi_awqos; assign main_core_outputs.ifu_axi_wvalid = ifu_axi_wvalid; assign main_core_outputs.ifu_axi_wdata = ifu_axi_wdata; assign main_core_outputs.ifu_axi_wstrb = ifu_axi_wstrb; assign main_core_outputs.ifu_axi_wlast = ifu_axi_wlast; assign main_core_outputs.ifu_axi_bready = ifu_axi_bready; assign main_core_outputs.ifu_axi_arvalid = ifu_axi_arvalid; assign main_core_outputs.ifu_axi_arid = ifu_axi_arid; assign main_core_outputs.ifu_axi_araddr = ifu_axi_araddr; assign main_core_outputs.ifu_axi_arregion = ifu_axi_arregion; assign main_core_outputs.ifu_axi_arlen = ifu_axi_arlen; assign main_core_outputs.ifu_axi_arsize = ifu_axi_arsize; assign main_core_outputs.ifu_axi_arburst = ifu_axi_arburst; assign main_core_outputs.ifu_axi_arlock = ifu_axi_arlock; assign main_core_outputs.ifu_axi_arcache = ifu_axi_arcache; assign main_core_outputs.ifu_axi_arprot = ifu_axi_arprot; assign main_core_outputs.ifu_axi_arqos = ifu_axi_arqos; assign main_core_outputs.ifu_axi_rready = ifu_axi_rready; assign main_core_outputs.sb_axi_awvalid = sb_axi_awvalid; assign main_core_outputs.sb_axi_awid = sb_axi_awid; assign main_core_outputs.sb_axi_awaddr = sb_axi_awaddr; assign main_core_outputs.sb_axi_awregion = sb_axi_awregion; assign main_core_outputs.sb_axi_awlen = sb_axi_awlen; assign main_core_outputs.sb_axi_awsize = sb_axi_awsize; assign main_core_outputs.sb_axi_awburst = sb_axi_awburst; assign main_core_outputs.sb_axi_awlock = sb_axi_awlock; assign main_core_outputs.sb_axi_awcache = sb_axi_awcache; assign main_core_outputs.sb_axi_awprot = sb_axi_awprot; assign main_core_outputs.sb_axi_awqos = sb_axi_awqos; assign main_core_outputs.sb_axi_wvalid = sb_axi_wvalid; assign main_core_outputs.sb_axi_wdata = sb_axi_wdata; assign main_core_outputs.sb_axi_wstrb = sb_axi_wstrb; assign main_core_outputs.sb_axi_wlast = sb_axi_wlast; assign main_core_outputs.sb_axi_bready = sb_axi_bready; assign main_core_outputs.sb_axi_arvalid = sb_axi_arvalid; assign main_core_outputs.sb_axi_arid = sb_axi_arid; assign main_core_outputs.sb_axi_araddr = sb_axi_araddr; assign main_core_outputs.sb_axi_arregion = sb_axi_arregion; assign main_core_outputs.sb_axi_arlen = sb_axi_arlen; assign main_core_outputs.sb_axi_arsize = sb_axi_arsize; assign main_core_outputs.sb_axi_arburst = sb_axi_arburst; assign main_core_outputs.sb_axi_arlock = sb_axi_arlock; assign main_core_outputs.sb_axi_arcache = sb_axi_arcache; assign main_core_outputs.sb_axi_arprot = sb_axi_arprot; assign main_core_outputs.sb_axi_arqos = sb_axi_arqos; assign main_core_outputs.sb_axi_rready = sb_axi_rready; assign main_core_outputs.dma_axi_awready = dma_axi_awready; assign main_core_outputs.dma_axi_wready = dma_axi_wready; assign main_core_outputs.dma_axi_bvalid = dma_axi_bvalid; assign main_core_outputs.dma_axi_bresp = dma_axi_bresp; assign main_core_outputs.dma_axi_bid = dma_axi_bid; assign main_core_outputs.dma_axi_arready = dma_axi_arready; assign main_core_outputs.dma_axi_rvalid = dma_axi_rvalid; assign main_core_outputs.dma_axi_rid = dma_axi_rid; assign main_core_outputs.dma_axi_rdata = dma_axi_rdata; assign main_core_outputs.dma_axi_rresp = dma_axi_rresp; assign main_core_outputs.dma_axi_rlast = dma_axi_rlast; assign main_core_outputs.haddr = haddr; assign main_core_outputs.hburst = hburst; assign main_core_outputs.hmastlock = hmastlock; assign main_core_outputs.hprot = hprot; assign main_core_outputs.hsize = hsize; assign main_core_outputs.htrans = htrans; assign main_core_outputs.hwrite = hwrite; assign main_core_outputs.lsu_haddr = lsu_haddr; assign main_core_outputs.lsu_hburst = lsu_hburst; assign main_core_outputs.lsu_hmastlock = lsu_hmastlock; assign main_core_outputs.lsu_hprot = lsu_hprot; assign main_core_outputs.lsu_hsize = lsu_hsize; assign main_core_outputs.lsu_htrans = lsu_htrans; assign main_core_outputs.lsu_hwrite = lsu_hwrite; assign main_core_outputs.lsu_hwdata = lsu_hwdata; assign main_core_outputs.sb_haddr = sb_haddr; assign main_core_outputs.sb_hburst = sb_hburst; assign main_core_outputs.sb_hmastlock = sb_hmastlock; assign main_core_outputs.sb_hprot = sb_hprot; assign main_core_outputs.sb_hsize = sb_hsize; assign main_core_outputs.sb_htrans = sb_htrans; assign main_core_outputs.sb_hwrite = sb_hwrite; assign main_core_outputs.sb_hwdata = sb_hwdata; assign main_core_outputs.dma_hrdata = dma_hrdata; assign main_core_outputs.dma_hreadyout = dma_hreadyout; assign main_core_outputs.dma_hresp = dma_hresp; assign main_core_outputs.dmi_reg_rdata = dmi_reg_rdata; assign main_core_outputs.iccm_ecc_single_error = iccm_ecc_single_error; assign main_core_outputs.iccm_ecc_double_error = iccm_ecc_double_error; assign main_core_outputs.dccm_ecc_single_error = dccm_ecc_single_error; assign main_core_outputs.dccm_ecc_double_error = dccm_ecc_double_error; // Shadow core enters reset immediately with main core but gets out of reset // after the delay logic [LockstepDelay:0] rst_shadow_sr, rst_dbg_shadow_sr; logic rst_shadow, rst_dbg_shadow; assign rst_shadow = &rst_shadow_sr; assign rst_dbg_shadow = &rst_dbg_shadow_sr; always_ff @(posedge clk or negedge rst_l) begin if (!rst_l) begin rst_shadow_sr <= '0; end else begin rst_shadow_sr <= (rst_shadow_sr << 1) + 1; end end always_ff @(posedge clk or negedge dbg_rst_l) begin if (!dbg_rst_l) begin rst_dbg_shadow_sr <= '0; end else begin rst_dbg_shadow_sr <= (rst_dbg_shadow_sr << 1) + 1; end end // Delay the inputs and outputs always_ff @(posedge clk or negedge rst_l) begin if (~rst_l) begin delay_input_d[0] <= veer_inputs_t'(0); delay_output_d[0] <= veer_outputs_t'(0); end else begin delay_input_d[0] <= main_core_inputs; delay_output_d[0] <= main_core_outputs; end end for (genvar i = 0; i < LockstepDelay; i++) begin always_ff @(posedge clk or negedge rst_l) begin if (!rst_l) begin delay_input_d[i+1] <= veer_inputs_t'(0); delay_output_d[i+1] <= veer_outputs_t'(0); end else begin delay_input_d[i+1] <= delay_input_d[i]; delay_output_d[i+1] <= delay_output_d[i]; end end end `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_regfile_if shadow_core_regfile (); el2_regfile_if delayed_main_core_regfile[LockstepDelay:0] (); always_ff @(posedge clk or negedge rst_l) begin if (!rst_l) begin delayed_main_core_regfile[0].gpr <= '0; delayed_main_core_regfile[0].tlu <= '0; end else begin delayed_main_core_regfile[0].gpr <= main_core_regfile.gpr; delayed_main_core_regfile[0].tlu <= main_core_regfile.tlu; end end for (genvar i = 0; i < LockstepDelay; i++) begin always_ff @(posedge clk or negedge rst_l) begin if (!rst_l) begin delayed_main_core_regfile[i+1].gpr <= '0; delayed_main_core_regfile[i+1].tlu <= '0; end else begin delayed_main_core_regfile[i+1].gpr <= delayed_main_core_regfile[i].gpr; delayed_main_core_regfile[i+1].tlu <= delayed_main_core_regfile[i].tlu; end end end `endif // Instantiate the el2_veer core el2_veer #( .pt(pt) ) xshadow_core ( `ifdef RV_LOCKSTEP_REGFILE_ENABLE .regfile(shadow_core_regfile.veer_rf_src), `endif .clk(clk), .rst_l(rst_shadow), .dbg_rst_l(rst_dbg_shadow), .rst_vec(shadow_core_inputs.rst_vec), .nmi_int(shadow_core_inputs.nmi_int), .nmi_vec(shadow_core_inputs.nmi_vec), .core_rst_l(shadow_core_outputs.core_rst_l), // we use those clocks from main core .active_l2clk(), .free_l2clk (), .trace_rv_i_insn_ip(shadow_core_outputs.trace_rv_i_insn_ip), .trace_rv_i_address_ip(shadow_core_outputs.trace_rv_i_address_ip), .trace_rv_i_valid_ip(shadow_core_outputs.trace_rv_i_valid_ip), .trace_rv_i_exception_ip(shadow_core_outputs.trace_rv_i_exception_ip), .trace_rv_i_ecause_ip(shadow_core_outputs.trace_rv_i_ecause_ip), .trace_rv_i_interrupt_ip(shadow_core_outputs.trace_rv_i_interrupt_ip), .trace_rv_i_tval_ip(shadow_core_outputs.trace_rv_i_tval_ip), .dccm_clk_override(shadow_core_outputs.dccm_clk_override), .icm_clk_override(shadow_core_outputs.icm_clk_override), .dec_tlu_core_ecc_disable(shadow_core_outputs.dec_tlu_core_ecc_disable), .i_cpu_halt_req(shadow_core_inputs.i_cpu_halt_req), .i_cpu_run_req(shadow_core_inputs.i_cpu_run_req), .o_cpu_halt_ack(shadow_core_outputs.o_cpu_halt_ack), .o_cpu_halt_status(shadow_core_outputs.o_cpu_halt_status), .o_cpu_run_ack(shadow_core_outputs.o_cpu_run_ack), .o_debug_mode_status(shadow_core_outputs.o_debug_mode_status), .core_id(core_id), .mpc_debug_halt_req(shadow_core_inputs.mpc_debug_halt_req), .mpc_debug_run_req (shadow_core_inputs.mpc_debug_run_req), .mpc_reset_run_req (shadow_core_inputs.mpc_reset_run_req), .mpc_debug_halt_ack(shadow_core_outputs.mpc_debug_halt_ack), .mpc_debug_run_ack (shadow_core_outputs.mpc_debug_run_ack), .debug_brkpt_status(shadow_core_outputs.debug_brkpt_status), .dec_tlu_perfcnt0(shadow_core_outputs.dec_tlu_perfcnt0), .dec_tlu_perfcnt1(shadow_core_outputs.dec_tlu_perfcnt1), .dec_tlu_perfcnt2(shadow_core_outputs.dec_tlu_perfcnt2), .dec_tlu_perfcnt3(shadow_core_outputs.dec_tlu_perfcnt3), .dccm_wren(shadow_core_outputs.dccm_wren), .dccm_rden(shadow_core_outputs.dccm_rden), .dccm_wr_addr_lo(shadow_core_outputs.dccm_wr_addr_lo), .dccm_wr_addr_hi(shadow_core_outputs.dccm_wr_addr_hi), .dccm_rd_addr_lo(shadow_core_outputs.dccm_rd_addr_lo), .dccm_rd_addr_hi(shadow_core_outputs.dccm_rd_addr_hi), .dccm_wr_data_lo(shadow_core_outputs.dccm_wr_data_lo), .dccm_wr_data_hi(shadow_core_outputs.dccm_wr_data_hi), .dccm_rd_data_lo(shadow_core_inputs.dccm_rd_data_lo), .dccm_rd_data_hi(shadow_core_inputs.dccm_rd_data_hi), .iccm_rw_addr(shadow_core_outputs.iccm_rw_addr), .iccm_wren(shadow_core_outputs.iccm_wren), .iccm_rden(shadow_core_outputs.iccm_rden), .iccm_wr_size(shadow_core_outputs.iccm_wr_size), .iccm_wr_data(shadow_core_outputs.iccm_wr_data), .iccm_buf_correct_ecc(shadow_core_outputs.iccm_buf_correct_ecc), .iccm_correction_state(shadow_core_outputs.iccm_correction_state), .iccm_rd_data(shadow_core_inputs.iccm_rd_data), .iccm_rd_data_ecc(shadow_core_inputs.iccm_rd_data_ecc), .ic_rw_addr(shadow_core_outputs.ic_rw_addr), .ic_tag_valid(shadow_core_outputs.ic_tag_valid), .ic_wr_en(shadow_core_outputs.ic_wr_en), .ic_rd_en(shadow_core_outputs.ic_rd_en), .ic_wr_data(shadow_core_outputs.ic_wr_data), .ic_rd_data(shadow_core_inputs.ic_rd_data), .ic_debug_rd_data(shadow_core_inputs.ic_debug_rd_data), .ictag_debug_rd_data(shadow_core_inputs.ictag_debug_rd_data), .ic_debug_wr_data(shadow_core_outputs.ic_debug_wr_data), .ic_eccerr(shadow_core_inputs.ic_eccerr), .ic_parerr(shadow_core_inputs.ic_parerr), .ic_premux_data(shadow_core_outputs.ic_premux_data), .ic_sel_premux_data(shadow_core_outputs.ic_sel_premux_data), .ic_debug_addr(shadow_core_outputs.ic_debug_addr), .ic_debug_rd_en(shadow_core_outputs.ic_debug_rd_en), .ic_debug_wr_en(shadow_core_outputs.ic_debug_wr_en), .ic_debug_tag_array(shadow_core_outputs.ic_debug_tag_array), .ic_debug_way(shadow_core_outputs.ic_debug_way), .ic_rd_hit (shadow_core_inputs.ic_rd_hit), .ic_tag_perr(shadow_core_inputs.ic_tag_perr), .lsu_axi_awvalid(shadow_core_outputs.lsu_axi_awvalid), .lsu_axi_awready(shadow_core_inputs.lsu_axi_awready), .lsu_axi_awid(shadow_core_outputs.lsu_axi_awid), .lsu_axi_awaddr(shadow_core_outputs.lsu_axi_awaddr), .lsu_axi_awregion(shadow_core_outputs.lsu_axi_awregion), .lsu_axi_awlen(shadow_core_outputs.lsu_axi_awlen), .lsu_axi_awsize(shadow_core_outputs.lsu_axi_awsize), .lsu_axi_awburst(shadow_core_outputs.lsu_axi_awburst), .lsu_axi_awlock(shadow_core_outputs.lsu_axi_awlock), .lsu_axi_awcache(shadow_core_outputs.lsu_axi_awcache), .lsu_axi_awprot(shadow_core_outputs.lsu_axi_awprot), .lsu_axi_awqos(shadow_core_outputs.lsu_axi_awqos), .lsu_axi_wvalid(shadow_core_outputs.lsu_axi_wvalid), .lsu_axi_wready(shadow_core_inputs.lsu_axi_wready), .lsu_axi_wdata(shadow_core_outputs.lsu_axi_wdata), .lsu_axi_wstrb(shadow_core_outputs.lsu_axi_wstrb), .lsu_axi_wlast(shadow_core_outputs.lsu_axi_wlast), .lsu_axi_bvalid(shadow_core_inputs.lsu_axi_bvalid), .lsu_axi_bready(shadow_core_outputs.lsu_axi_bready), .lsu_axi_bresp(shadow_core_inputs.lsu_axi_bresp), .lsu_axi_bid(shadow_core_inputs.lsu_axi_bid), .lsu_axi_arvalid(shadow_core_outputs.lsu_axi_arvalid), .lsu_axi_arready(shadow_core_inputs.lsu_axi_arready), .lsu_axi_arid(shadow_core_outputs.lsu_axi_arid), .lsu_axi_araddr(shadow_core_outputs.lsu_axi_araddr), .lsu_axi_arregion(shadow_core_outputs.lsu_axi_arregion), .lsu_axi_arlen(shadow_core_outputs.lsu_axi_arlen), .lsu_axi_arsize(shadow_core_outputs.lsu_axi_arsize), .lsu_axi_arburst(shadow_core_outputs.lsu_axi_arburst), .lsu_axi_arlock(shadow_core_outputs.lsu_axi_arlock), .lsu_axi_arcache(shadow_core_outputs.lsu_axi_arcache), .lsu_axi_arprot(shadow_core_outputs.lsu_axi_arprot), .lsu_axi_arqos(shadow_core_outputs.lsu_axi_arqos), .lsu_axi_rvalid(shadow_core_inputs.lsu_axi_rvalid), .lsu_axi_rready(shadow_core_outputs.lsu_axi_rready), .lsu_axi_rid(shadow_core_inputs.lsu_axi_rid), .lsu_axi_rdata(shadow_core_inputs.lsu_axi_rdata), .lsu_axi_rresp(shadow_core_inputs.lsu_axi_rresp), .lsu_axi_rlast(shadow_core_inputs.lsu_axi_rlast), .ifu_axi_awvalid(shadow_core_outputs.ifu_axi_awvalid), .ifu_axi_awready(shadow_core_inputs.ifu_axi_awready), .ifu_axi_awid(shadow_core_outputs.ifu_axi_awid), .ifu_axi_awaddr(shadow_core_outputs.ifu_axi_awaddr), .ifu_axi_awregion(shadow_core_outputs.ifu_axi_awregion), .ifu_axi_awlen(shadow_core_outputs.ifu_axi_awlen), .ifu_axi_awsize(shadow_core_outputs.ifu_axi_awsize), .ifu_axi_awburst(shadow_core_outputs.ifu_axi_awburst), .ifu_axi_awlock(shadow_core_outputs.ifu_axi_awlock), .ifu_axi_awcache(shadow_core_outputs.ifu_axi_awcache), .ifu_axi_awprot(shadow_core_outputs.ifu_axi_awprot), .ifu_axi_awqos(shadow_core_outputs.ifu_axi_awqos), .ifu_axi_wvalid(shadow_core_outputs.ifu_axi_wvalid), .ifu_axi_wready(shadow_core_inputs.ifu_axi_wready), .ifu_axi_wdata(shadow_core_outputs.ifu_axi_wdata), .ifu_axi_wstrb(shadow_core_outputs.ifu_axi_wstrb), .ifu_axi_wlast(shadow_core_outputs.ifu_axi_wlast), .ifu_axi_bvalid(shadow_core_inputs.ifu_axi_bvalid), .ifu_axi_bready(shadow_core_outputs.ifu_axi_bready), .ifu_axi_bresp(shadow_core_inputs.ifu_axi_bresp), .ifu_axi_bid(shadow_core_inputs.ifu_axi_bid), .ifu_axi_arvalid(shadow_core_outputs.ifu_axi_arvalid), .ifu_axi_arready(shadow_core_inputs.ifu_axi_arready), .ifu_axi_arid(shadow_core_outputs.ifu_axi_arid), .ifu_axi_araddr(shadow_core_outputs.ifu_axi_araddr), .ifu_axi_arregion(shadow_core_outputs.ifu_axi_arregion), .ifu_axi_arlen(shadow_core_outputs.ifu_axi_arlen), .ifu_axi_arsize(shadow_core_outputs.ifu_axi_arsize), .ifu_axi_arburst(shadow_core_outputs.ifu_axi_arburst), .ifu_axi_arlock(shadow_core_outputs.ifu_axi_arlock), .ifu_axi_arcache(shadow_core_outputs.ifu_axi_arcache), .ifu_axi_arprot(shadow_core_outputs.ifu_axi_arprot), .ifu_axi_arqos(shadow_core_outputs.ifu_axi_arqos), .ifu_axi_rvalid(shadow_core_inputs.ifu_axi_rvalid), .ifu_axi_rready(shadow_core_outputs.ifu_axi_rready), .ifu_axi_rid(shadow_core_inputs.ifu_axi_rid), .ifu_axi_rdata(shadow_core_inputs.ifu_axi_rdata), .ifu_axi_rresp(shadow_core_inputs.ifu_axi_rresp), .ifu_axi_rlast(shadow_core_inputs.ifu_axi_rlast), .sb_axi_awvalid(shadow_core_outputs.sb_axi_awvalid), .sb_axi_awready(shadow_core_inputs.sb_axi_awready), .sb_axi_awid(shadow_core_outputs.sb_axi_awid), .sb_axi_awaddr(shadow_core_outputs.sb_axi_awaddr), .sb_axi_awregion(shadow_core_outputs.sb_axi_awregion), .sb_axi_awlen(shadow_core_outputs.sb_axi_awlen), .sb_axi_awsize(shadow_core_outputs.sb_axi_awsize), .sb_axi_awburst(shadow_core_outputs.sb_axi_awburst), .sb_axi_awlock(shadow_core_outputs.sb_axi_awlock), .sb_axi_awcache(shadow_core_outputs.sb_axi_awcache), .sb_axi_awprot(shadow_core_outputs.sb_axi_awprot), .sb_axi_awqos(shadow_core_outputs.sb_axi_awqos), .sb_axi_wvalid(shadow_core_outputs.sb_axi_wvalid), .sb_axi_wready(shadow_core_inputs.sb_axi_wready), .sb_axi_wdata(shadow_core_outputs.sb_axi_wdata), .sb_axi_wstrb(shadow_core_outputs.sb_axi_wstrb), .sb_axi_wlast(shadow_core_outputs.sb_axi_wlast), .sb_axi_bvalid(shadow_core_inputs.sb_axi_bvalid), .sb_axi_bready(shadow_core_outputs.sb_axi_bready), .sb_axi_bresp(shadow_core_inputs.sb_axi_bresp), .sb_axi_bid(shadow_core_inputs.sb_axi_bid), .sb_axi_arvalid(shadow_core_outputs.sb_axi_arvalid), .sb_axi_arready(shadow_core_inputs.sb_axi_arready), .sb_axi_arid(shadow_core_outputs.sb_axi_arid), .sb_axi_araddr(shadow_core_outputs.sb_axi_araddr), .sb_axi_arregion(shadow_core_outputs.sb_axi_arregion), .sb_axi_arlen(shadow_core_outputs.sb_axi_arlen), .sb_axi_arsize(shadow_core_outputs.sb_axi_arsize), .sb_axi_arburst(shadow_core_outputs.sb_axi_arburst), .sb_axi_arlock(shadow_core_outputs.sb_axi_arlock), .sb_axi_arcache(shadow_core_outputs.sb_axi_arcache), .sb_axi_arprot(shadow_core_outputs.sb_axi_arprot), .sb_axi_arqos(shadow_core_outputs.sb_axi_arqos), .sb_axi_rvalid(shadow_core_inputs.sb_axi_rvalid), .sb_axi_rready(shadow_core_outputs.sb_axi_rready), .sb_axi_rid(shadow_core_inputs.sb_axi_rid), .sb_axi_rdata(shadow_core_inputs.sb_axi_rdata), .sb_axi_rresp(shadow_core_inputs.sb_axi_rresp), .sb_axi_rlast(shadow_core_inputs.sb_axi_rlast), .dma_axi_awvalid(shadow_core_inputs.dma_axi_awvalid), .dma_axi_awready(shadow_core_outputs.dma_axi_awready), .dma_axi_awid(shadow_core_inputs.dma_axi_awid), .dma_axi_awaddr(shadow_core_inputs.dma_axi_awaddr), .dma_axi_awsize(shadow_core_inputs.dma_axi_awsize), .dma_axi_awprot(shadow_core_inputs.dma_axi_awprot), .dma_axi_awlen(shadow_core_inputs.dma_axi_awlen), .dma_axi_awburst(shadow_core_inputs.dma_axi_awburst), .dma_axi_wvalid(shadow_core_inputs.dma_axi_wvalid), .dma_axi_wready(shadow_core_outputs.dma_axi_wready), .dma_axi_wdata(shadow_core_inputs.dma_axi_wdata), .dma_axi_wstrb(shadow_core_inputs.dma_axi_wstrb), .dma_axi_wlast(shadow_core_inputs.dma_axi_wlast), .dma_axi_bvalid(shadow_core_outputs.dma_axi_bvalid), .dma_axi_bready(shadow_core_inputs.dma_axi_bready), .dma_axi_bresp(shadow_core_outputs.dma_axi_bresp), .dma_axi_bid(shadow_core_outputs.dma_axi_bid), .dma_axi_arvalid(shadow_core_inputs.dma_axi_arvalid), .dma_axi_arready(shadow_core_outputs.dma_axi_arready), .dma_axi_arid(shadow_core_inputs.dma_axi_arid), .dma_axi_araddr(shadow_core_inputs.dma_axi_araddr), .dma_axi_arsize(shadow_core_inputs.dma_axi_arsize), .dma_axi_arprot(shadow_core_inputs.dma_axi_arprot), .dma_axi_arlen(shadow_core_inputs.dma_axi_arlen), .dma_axi_arburst(shadow_core_inputs.dma_axi_arburst), .dma_axi_rvalid(shadow_core_outputs.dma_axi_rvalid), .dma_axi_rready(shadow_core_inputs.dma_axi_rready), .dma_axi_rid(shadow_core_outputs.dma_axi_rid), .dma_axi_rdata(shadow_core_outputs.dma_axi_rdata), .dma_axi_rresp(shadow_core_outputs.dma_axi_rresp), .dma_axi_rlast(shadow_core_outputs.dma_axi_rlast), .haddr(shadow_core_outputs.haddr), .hburst(shadow_core_outputs.hburst), .hmastlock(shadow_core_outputs.hmastlock), .hprot(shadow_core_outputs.hprot), .hsize(shadow_core_outputs.hsize), .htrans(shadow_core_outputs.htrans), .hwrite(shadow_core_outputs.hwrite), .hrdata(shadow_core_inputs.hrdata), .hready(shadow_core_inputs.hready), .hresp(shadow_core_inputs.hresp), .lsu_haddr(shadow_core_outputs.lsu_haddr), .lsu_hburst(shadow_core_outputs.lsu_hburst), .lsu_hmastlock(shadow_core_outputs.lsu_hmastlock), .lsu_hprot(shadow_core_outputs.lsu_hprot), .lsu_hsize(shadow_core_outputs.lsu_hsize), .lsu_htrans(shadow_core_outputs.lsu_htrans), .lsu_hwrite(shadow_core_outputs.lsu_hwrite), .lsu_hwdata(shadow_core_outputs.lsu_hwdata), .lsu_hrdata(shadow_core_inputs.lsu_hrdata), .lsu_hready(shadow_core_inputs.lsu_hready), .lsu_hresp(shadow_core_inputs.lsu_hresp), .sb_haddr(shadow_core_outputs.sb_haddr), .sb_hburst(shadow_core_outputs.sb_hburst), .sb_hmastlock(shadow_core_outputs.sb_hmastlock), .sb_hprot(shadow_core_outputs.sb_hprot), .sb_hsize(shadow_core_outputs.sb_hsize), .sb_htrans(shadow_core_outputs.sb_htrans), .sb_hwrite(shadow_core_outputs.sb_hwrite), .sb_hwdata(shadow_core_outputs.sb_hwdata), .sb_hrdata(shadow_core_inputs.sb_hrdata), .sb_hready(shadow_core_inputs.sb_hready), .sb_hresp(shadow_core_inputs.sb_hresp), .dma_hsel(shadow_core_inputs.dma_hsel), .dma_haddr(shadow_core_inputs.dma_haddr), .dma_hburst(shadow_core_inputs.dma_hburst), .dma_hmastlock(shadow_core_inputs.dma_hmastlock), .dma_hprot(shadow_core_inputs.dma_hprot), .dma_hsize(shadow_core_inputs.dma_hsize), .dma_htrans(shadow_core_inputs.dma_htrans), .dma_hwrite(shadow_core_inputs.dma_hwrite), .dma_hwdata(shadow_core_inputs.dma_hwdata), .dma_hreadyin(shadow_core_inputs.dma_hreadyin), .dma_hrdata(shadow_core_outputs.dma_hrdata), .dma_hreadyout(shadow_core_outputs.dma_hreadyout), .dma_hresp(shadow_core_outputs.dma_hresp), .lsu_bus_clk_en(shadow_core_inputs.lsu_bus_clk_en), .ifu_bus_clk_en(shadow_core_inputs.ifu_bus_clk_en), .dbg_bus_clk_en(shadow_core_inputs.dbg_bus_clk_en), .dma_bus_clk_en(shadow_core_inputs.dma_bus_clk_en), .dmi_reg_en(shadow_core_inputs.dmi_reg_en), .dmi_reg_addr(shadow_core_inputs.dmi_reg_addr), .dmi_reg_wr_en(shadow_core_inputs.dmi_reg_wr_en), .dmi_reg_wdata(shadow_core_inputs.dmi_reg_wdata), .dmi_reg_rdata(shadow_core_outputs.dmi_reg_rdata), .iccm_ecc_single_error(shadow_core_outputs.iccm_ecc_single_error), .iccm_ecc_double_error(shadow_core_outputs.iccm_ecc_double_error), .dccm_ecc_single_error(shadow_core_outputs.dccm_ecc_single_error), .dccm_ecc_double_error(shadow_core_outputs.dccm_ecc_double_error), .extintsrc_req(shadow_core_inputs.extintsrc_req), .timer_int(shadow_core_inputs.timer_int), .soft_int(shadow_core_inputs.soft_int), .scan_mode(shadow_core_inputs.scan_mode) ); // Equivalence Check logic rst_n; assign rst_n = rst_shadow & rst_dbg_shadow; logic corruption_detected, outputs_corrupted; assign outputs_corrupted = delayed_main_core_outputs != shadow_core_outputs; `ifdef RV_LOCKSTEP_REGFILE_ENABLE logic regfile_corrupted; assign regfile_corrupted = (delayed_main_core_regfile[LockstepDelay].gpr != shadow_core_regfile.gpr) | (delayed_main_core_regfile[LockstepDelay].tlu != shadow_core_regfile.tlu); assign corruption_detected = outputs_corrupted | regfile_corrupted; `else assign corruption_detected = outputs_corrupted; `endif // Report corruption if all of the below requirements are fulfilled: // - IOs of Main Core and Shadow Core differ OR error injection is enabled // - Shadow Core is out of reset // - Shadow Core is enabled assign corruption_detected_o = ((corruption_detected | lockstep_err_injection_en_i) & rst_n) & ~disable_corruption_detection_i; endmodule : el2_veer_lockstep ================================================ FILE: design/el2_veer_wrapper.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // Copyright (c) 2023 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // Function: Top wrapper file with el2_veer/mem instantiated inside // Comments: // //******************************************************************************** module el2_veer_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic dbg_rst_l, // rst_vec is supposed to be tied to constant in the top level /*pragma coverage off*/ input logic [31:1] rst_vec, /*pragma coverage on*/ input logic nmi_int, // jtag_id and nmi_vec are supposed to be tied to constants in the top level /*pragma coverage off*/ input logic [31:1] nmi_vec, input logic [31:1] jtag_id, /*pragma coverage on*/ output logic [31:0] trace_rv_i_insn_ip, output logic [31:0] trace_rv_i_address_ip, output logic trace_rv_i_valid_ip, output logic trace_rv_i_exception_ip, output logic [4:0] trace_rv_i_ecause_ip, output logic trace_rv_i_interrupt_ip, output logic [31:0] trace_rv_i_tval_ip, // Bus signals `ifdef RV_BUILD_AXI4 //-------------------------- LSU AXI signals-------------------------- // AXI Write Channels output logic lsu_axi_awvalid, input logic lsu_axi_awready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid, output logic [31:0] lsu_axi_awaddr, output logic [3:0] lsu_axi_awregion, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [7:0] lsu_axi_awlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_awsize, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [1:0] lsu_axi_awburst, output logic lsu_axi_awlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_awcache, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [2:0] lsu_axi_awprot, output logic [3:0] lsu_axi_awqos, /*pragma coverage on*/ output logic lsu_axi_wvalid, input logic lsu_axi_wready, output logic [63:0] lsu_axi_wdata, output logic [7:0] lsu_axi_wstrb, output logic lsu_axi_wlast, input logic lsu_axi_bvalid, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic lsu_axi_bready, /*pragma coverage on*/ input logic [1:0] lsu_axi_bresp, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid, // AXI Read Channels output logic lsu_axi_arvalid, input logic lsu_axi_arready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid, output logic [31:0] lsu_axi_araddr, output logic [3:0] lsu_axi_arregion, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [7:0] lsu_axi_arlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_arsize, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [1:0] lsu_axi_arburst, output logic lsu_axi_arlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_arcache, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [2:0] lsu_axi_arprot, output logic [3:0] lsu_axi_arqos, /*pragma coverage on*/ input logic lsu_axi_rvalid, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic lsu_axi_rready, /*pragma coverage on*/ input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid, input logic [63:0] lsu_axi_rdata, input logic [1:0] lsu_axi_rresp, input logic lsu_axi_rlast, //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv IFU does not use AXI write channel */ /*pragma coverage off*/ output logic ifu_axi_awvalid, input logic ifu_axi_awready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid, output logic [31:0] ifu_axi_awaddr, output logic [3:0] ifu_axi_awregion, output logic [7:0] ifu_axi_awlen, output logic [2:0] ifu_axi_awsize, output logic [1:0] ifu_axi_awburst, output logic ifu_axi_awlock, output logic [3:0] ifu_axi_awcache, output logic [2:0] ifu_axi_awprot, output logic [3:0] ifu_axi_awqos, output logic ifu_axi_wvalid, input logic ifu_axi_wready, output logic [63:0] ifu_axi_wdata, output logic [7:0] ifu_axi_wstrb, output logic ifu_axi_wlast, input logic ifu_axi_bvalid, output logic ifu_axi_bready, input logic [1:0] ifu_axi_bresp, input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_bid, /*pragma coverage on*/ // AXI Read Channels output logic ifu_axi_arvalid, input logic ifu_axi_arready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid, output logic [31:0] ifu_axi_araddr, output logic [3:0] ifu_axi_arregion, /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv */ /*pragma coverage off*/ output logic [7:0] ifu_axi_arlen, output logic [2:0] ifu_axi_arsize, output logic [1:0] ifu_axi_arburst, output logic ifu_axi_arlock, output logic [3:0] ifu_axi_arcache, output logic [2:0] ifu_axi_arprot, output logic [3:0] ifu_axi_arqos, /*pragma coverage on*/ input logic ifu_axi_rvalid, /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv */ /*pragma coverage off*/ output logic ifu_axi_rready, /*pragma coverage on*/ input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid, input logic [63:0] ifu_axi_rdata, input logic [1:0] ifu_axi_rresp, input logic ifu_axi_rlast, //-------------------------- SB AXI signals-------------------------- // AXI Write Channels output logic sb_axi_awvalid, input logic sb_axi_awready, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [pt.SB_BUS_TAG-1:0] sb_axi_awid, /*pragma coverage on*/ output logic [31:0] sb_axi_awaddr, output logic [3:0] sb_axi_awregion, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [7:0] sb_axi_awlen, /*pragma coverage on*/ output logic [2:0] sb_axi_awsize, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [1:0] sb_axi_awburst, output logic sb_axi_awlock, output logic [3:0] sb_axi_awcache, output logic [2:0] sb_axi_awprot, output logic [3:0] sb_axi_awqos, /*pragma coverage on*/ output logic sb_axi_wvalid, input logic sb_axi_wready, output logic [63:0] sb_axi_wdata, output logic [7:0] sb_axi_wstrb, output logic sb_axi_wlast, input logic sb_axi_bvalid, output logic sb_axi_bready, input logic [1:0] sb_axi_bresp, input logic [pt.SB_BUS_TAG-1:0] sb_axi_bid, // AXI Read Channels output logic sb_axi_arvalid, input logic sb_axi_arready, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [pt.SB_BUS_TAG-1:0] sb_axi_arid, /*pragma coverage on*/ output logic [31:0] sb_axi_araddr, output logic [3:0] sb_axi_arregion, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [7:0] sb_axi_arlen, /*pragma coverage on*/ output logic [2:0] sb_axi_arsize, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic [1:0] sb_axi_arburst, output logic sb_axi_arlock, output logic [3:0] sb_axi_arcache, output logic [2:0] sb_axi_arprot, output logic [3:0] sb_axi_arqos, /*pragma coverage on*/ input logic sb_axi_rvalid, /* exclude signals that are tied to constant value in dbg/el2_dbg.sv */ /*pragma coverage off*/ output logic sb_axi_rready, /*pragma coverage on*/ input logic [pt.SB_BUS_TAG-1:0] sb_axi_rid, input logic [63:0] sb_axi_rdata, input logic [1:0] sb_axi_rresp, input logic sb_axi_rlast, //-------------------------- DMA AXI signals-------------------------- // AXI Write Channels input logic dma_axi_awvalid, output logic dma_axi_awready, /* exclude signals that are tied to constant value in tb_top.sv */ /*pragma coverage off*/ input logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid, /*pragma coverage on*/ input logic [31:0] dma_axi_awaddr, input logic [2:0] dma_axi_awsize, input logic [2:0] dma_axi_awprot, input logic [7:0] dma_axi_awlen, input logic [1:0] dma_axi_awburst, input logic dma_axi_wvalid, output logic dma_axi_wready, input logic [63:0] dma_axi_wdata, input logic [7:0] dma_axi_wstrb, input logic dma_axi_wlast, output logic dma_axi_bvalid, input logic dma_axi_bready, output logic [1:0] dma_axi_bresp, output logic [pt.DMA_BUS_TAG-1:0] dma_axi_bid, // AXI Read Channels input logic dma_axi_arvalid, output logic dma_axi_arready, /* exclude signals that are tied to constant value in tb_top.sv */ /*pragma coverage off*/ input logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid, /*pragma coverage on*/ input logic [31:0] dma_axi_araddr, input logic [2:0] dma_axi_arsize, input logic [2:0] dma_axi_arprot, input logic [7:0] dma_axi_arlen, input logic [1:0] dma_axi_arburst, output logic dma_axi_rvalid, input logic dma_axi_rready, output logic [pt.DMA_BUS_TAG-1:0] dma_axi_rid, output logic [63:0] dma_axi_rdata, output logic [1:0] dma_axi_rresp, output logic dma_axi_rlast, `endif `ifdef RV_BUILD_AHB_LITE //// AHB LITE BUS output logic [31:0] haddr, /* exclude signals that are tied to constant value in axi4_to_ahb.sv */ /*pragma coverage off*/ output logic [2:0] hburst, output logic hmastlock, /*pragma coverage on*/ output logic [3:0] hprot, output logic [2:0] hsize, output logic [1:0] htrans, output logic hwrite, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ input logic [63:0] hrdata, input logic hready, input logic hresp, /*pragma coverage on*/ // LSU AHB Master output logic [31:0] lsu_haddr, /* exclude signals that are tied to constant value in axi4_to_ahb.sv */ /*pragma coverage off*/ output logic [2:0] lsu_hburst, output logic lsu_hmastlock, /*pragma coverage on*/ output logic [3:0] lsu_hprot, output logic [2:0] lsu_hsize, output logic [1:0] lsu_htrans, output logic lsu_hwrite, output logic [63:0] lsu_hwdata, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ input logic [63:0] lsu_hrdata, input logic lsu_hready, input logic lsu_hresp, /*pragma coverage on*/ // Debug System Bus AHB output logic [31:0] sb_haddr, /* exclude signals that are tied to constant value in axi4_to_ahb.sv */ /*pragma coverage off*/ output logic [2:0] sb_hburst, output logic sb_hmastlock, /*pragma coverage on*/ output logic [3:0] sb_hprot, output logic [2:0] sb_hsize, output logic [1:0] sb_htrans, output logic sb_hwrite, output logic [63:0] sb_hwdata, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ input logic [63:0] sb_hrdata, input logic sb_hready, input logic sb_hresp, /*pragma coverage on*/ // DMA Slave /* exclude signals that are tied to constant value in tb_top.sv */ /*pragma coverage off*/ input logic dma_hsel, input logic [31:0] dma_haddr, input logic [2:0] dma_hburst, input logic dma_hmastlock, input logic [3:0] dma_hprot, input logic [2:0] dma_hsize, input logic [1:0] dma_htrans, input logic dma_hwrite, input logic [63:0] dma_hwdata, /*pragma coverage on*/ input logic dma_hreadyin, output logic [63:0] dma_hrdata, output logic dma_hreadyout, output logic dma_hresp, `endif // clk ratio signals input logic lsu_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface input logic ifu_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface input logic dbg_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface input logic dma_bus_clk_en, // Clock ratio b/w cpu core clk & AHB slave interface // ICCM/DCCM ECC status output logic iccm_ecc_single_error, output logic iccm_ecc_double_error, output logic dccm_ecc_single_error, output logic dccm_ecc_double_error, // ICache export interface el2_mem_if.veer_icache_src el2_icache_export, input logic timer_int, input logic soft_int, input logic [pt.PIC_TOTAL_INT:1] extintsrc_req, output logic dec_tlu_perfcnt0, // toggles when slot0 perf counter 0 has an event inc output logic dec_tlu_perfcnt1, output logic dec_tlu_perfcnt2, output logic dec_tlu_perfcnt3, // ports added by the soc team input logic jtag_tck, // JTAG clk input logic jtag_tms, // JTAG TMS input logic jtag_tdi, // JTAG tdi input logic jtag_trst_n, // JTAG Reset output logic jtag_tdo, // JTAG TDO output logic jtag_tdoEn, // JTAG Test Data Output enable /*pragma coverage off*/ input logic [31:4] core_id, /*pragma coverage on*/ // Memory Export Interface el2_mem_if.veer_sram_src el2_mem_export, `ifdef RV_LOCKSTEP_ENABLE // Shadow Core control input logic disable_corruption_detection_i, input logic lockstep_err_injection_en_i, output logic corruption_detected_o, `endif // external MPC halt/run interface input logic mpc_debug_halt_req, // Async halt request input logic mpc_debug_run_req, // Async run request input logic mpc_reset_run_req, // Run/halt after reset output logic mpc_debug_halt_ack, // Halt ack output logic mpc_debug_run_ack, // Run ack output logic debug_brkpt_status, // debug breakpoint input logic i_cpu_halt_req, // Async halt req to CPU output logic o_cpu_halt_ack, // core response to halt output logic o_cpu_halt_status, // 1'b1 indicates core is halted output logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request input logic i_cpu_run_req, // Async restart req to CPU output logic o_cpu_run_ack, // Core response to run req // Excluding scan_mode and mbist_mode from coverage as their usage is determined by the integrator of the VeeR core. /* pragma coverage off */ input logic scan_mode, // To enable scan mode input logic mbist_mode, // to enable mbist // DMI port for uncore input logic dmi_core_enable, input logic dmi_uncore_enable, output logic dmi_uncore_en, output logic dmi_uncore_wr_en, output logic [ 6:0] dmi_uncore_addr, output logic [31:0] dmi_uncore_wdata, input logic [31:0] dmi_uncore_rdata, output logic dmi_active /* pragma coverage on */ ); logic active_l2clk; logic free_l2clk; // DCCM ports logic dccm_wren; logic dccm_rden; logic [pt.DCCM_BITS-1:0] dccm_wr_addr_lo; logic [pt.DCCM_BITS-1:0] dccm_wr_addr_hi; logic [pt.DCCM_BITS-1:0] dccm_rd_addr_lo; logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi; // PIC ports // Icache & Itag ports logic [31:1] ic_rw_addr; logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en ; // Which way to write logic ic_rd_en ; logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid; // Valid from the I$ tag valid outside (in flops). logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit; // ic_rd_hit[3:0] logic ic_tag_perr; // Ic tag parity error logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr; // Read/Write addresss to the Icache. logic ic_debug_rd_en; // Icache debug rd logic ic_debug_wr_en; // Icache debug wr logic ic_debug_tag_array; // Debug tag array logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way; // Debug way. Rd or Wr. logic [25:0] ictag_debug_rd_data; // Debug icache tag. logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data; logic [63:0] ic_rd_data; logic [70:0] ic_debug_rd_data; // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC logic [70:0] ic_debug_wr_data; // Debug wr cache. logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr; // ecc error per bank logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr; // parity error per bank logic [63:0] ic_premux_data; logic ic_sel_premux_data; // ICCM ports logic [pt.ICCM_BITS-1:1] iccm_rw_addr; logic iccm_wren; logic iccm_rden; logic [2:0] iccm_wr_size; logic [77:0] iccm_wr_data; logic iccm_buf_correct_ecc; logic iccm_correction_state; logic [63:0] iccm_rd_data; logic [77:0] iccm_rd_data_ecc; logic core_rst_l; // Core reset including rst_l and dbg_rst_l logic dccm_clk_override; logic icm_clk_override; logic dec_tlu_core_ecc_disable; // zero out the signals not presented at the wrapper instantiation level `ifdef RV_BUILD_AXI4 // Since all the signals in this block are tied to constant, we exclude this from coverage analysis /*pragma coverage off*/ //// AHB LITE BUS logic [31:0] haddr; logic [2:0] hburst; logic hmastlock; logic [3:0] hprot; logic [2:0] hsize; logic [1:0] htrans; logic hwrite; logic [63:0] hrdata; logic hready; logic hresp; // LSU AHB Master logic [31:0] lsu_haddr; logic [2:0] lsu_hburst; logic lsu_hmastlock; logic [3:0] lsu_hprot; logic [2:0] lsu_hsize; logic [1:0] lsu_htrans; logic lsu_hwrite; logic [63:0] lsu_hwdata; logic [63:0] lsu_hrdata; logic lsu_hready; logic lsu_hresp; // Debug System Bus AHB logic [31:0] sb_haddr; logic [2:0] sb_hburst; logic sb_hmastlock; logic [3:0] sb_hprot; logic [2:0] sb_hsize; logic [1:0] sb_htrans; logic sb_hwrite; logic [63:0] sb_hwdata; logic [63:0] sb_hrdata; logic sb_hready; logic sb_hresp; // DMA Slave logic dma_hsel; logic [31:0] dma_haddr; logic [2:0] dma_hburst; logic dma_hmastlock; logic [3:0] dma_hprot; logic [2:0] dma_hsize; logic [1:0] dma_htrans; logic dma_hwrite; logic [63:0] dma_hwdata; logic dma_hreadyin; logic [63:0] dma_hrdata; logic dma_hreadyout; logic dma_hresp; // AHB assign hrdata[63:0] = '0; assign hready = '0; assign hresp = '0; // LSU assign lsu_hrdata[63:0] = '0; assign lsu_hready = '0; assign lsu_hresp = '0; // Debu assign sb_hrdata[63:0] = '0; assign sb_hready = '0; assign sb_hresp = '0; // DMA assign dma_hsel = '0; assign dma_haddr[31:0] = '0; assign dma_hburst[2:0] = '0; assign dma_hmastlock = '0; assign dma_hprot[3:0] = '0; assign dma_hsize[2:0] = '0; assign dma_htrans[1:0] = '0; assign dma_hwrite = '0; assign dma_hwdata[63:0] = '0; assign dma_hreadyin = '0; /*pragma coverage on*/ `endif // `ifdef RV_BUILD_AXI4 `ifdef RV_BUILD_AHB_LITE // Since all the signals in this block are tied to constant, we exclude this from coverage analysis /*pragma coverage off*/ wire lsu_axi_awvalid; wire lsu_axi_awready; wire [pt.LSU_BUS_TAG-1:0] lsu_axi_awid; wire [31:0] lsu_axi_awaddr; wire [3:0] lsu_axi_awregion; wire [7:0] lsu_axi_awlen; wire [2:0] lsu_axi_awsize; wire [1:0] lsu_axi_awburst; wire lsu_axi_awlock; wire [3:0] lsu_axi_awcache; wire [2:0] lsu_axi_awprot; wire [3:0] lsu_axi_awqos; wire lsu_axi_wvalid; wire lsu_axi_wready; wire [63:0] lsu_axi_wdata; wire [7:0] lsu_axi_wstrb; wire lsu_axi_wlast; wire lsu_axi_bvalid; wire lsu_axi_bready; wire [1:0] lsu_axi_bresp; wire [pt.LSU_BUS_TAG-1:0] lsu_axi_bid; // AXI Read Channels wire lsu_axi_arvalid; wire lsu_axi_arready; wire [pt.LSU_BUS_TAG-1:0] lsu_axi_arid; wire [31:0] lsu_axi_araddr; wire [3:0] lsu_axi_arregion; wire [7:0] lsu_axi_arlen; wire [2:0] lsu_axi_arsize; wire [1:0] lsu_axi_arburst; wire lsu_axi_arlock; wire [3:0] lsu_axi_arcache; wire [2:0] lsu_axi_arprot; wire [3:0] lsu_axi_arqos; wire lsu_axi_rvalid; wire lsu_axi_rready; wire [pt.LSU_BUS_TAG-1:0] lsu_axi_rid; wire [63:0] lsu_axi_rdata; wire [1:0] lsu_axi_rresp; wire lsu_axi_rlast; assign lsu_axi_awready = '0; assign lsu_axi_wready = '0; assign lsu_axi_bvalid = '0; assign lsu_axi_bresp = '0; assign lsu_axi_bid = {pt.LSU_BUS_TAG{1'b0}}; assign lsu_axi_arready = '0; assign lsu_axi_rvalid = '0; assign lsu_axi_rid = {pt.LSU_BUS_TAG{1'b0}}; assign lsu_axi_rdata = '0; assign lsu_axi_rresp = '0; assign lsu_axi_rlast = '0; //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels wire ifu_axi_awvalid; wire ifu_axi_awready; wire [pt.IFU_BUS_TAG-1:0] ifu_axi_awid; wire [31:0] ifu_axi_awaddr; wire [3:0] ifu_axi_awregion; wire [7:0] ifu_axi_awlen; wire [2:0] ifu_axi_awsize; wire [1:0] ifu_axi_awburst; wire ifu_axi_awlock; wire [3:0] ifu_axi_awcache; wire [2:0] ifu_axi_awprot; wire [3:0] ifu_axi_awqos; wire ifu_axi_wvalid; wire ifu_axi_wready; wire [63:0] ifu_axi_wdata; wire [7:0] ifu_axi_wstrb; wire ifu_axi_wlast; wire ifu_axi_bvalid; wire ifu_axi_bready; wire [1:0] ifu_axi_bresp; wire [pt.IFU_BUS_TAG-1:0] ifu_axi_bid; // AXI Read Channels wire ifu_axi_arvalid; wire ifu_axi_arready; wire [pt.IFU_BUS_TAG-1:0] ifu_axi_arid; wire [31:0] ifu_axi_araddr; wire [3:0] ifu_axi_arregion; wire [7:0] ifu_axi_arlen; wire [2:0] ifu_axi_arsize; wire [1:0] ifu_axi_arburst; wire ifu_axi_arlock; wire [3:0] ifu_axi_arcache; wire [2:0] ifu_axi_arprot; wire [3:0] ifu_axi_arqos; wire ifu_axi_rvalid; wire ifu_axi_rready; wire [pt.IFU_BUS_TAG-1:0] ifu_axi_rid; wire [63:0] ifu_axi_rdata; wire [1:0] ifu_axi_rresp; wire ifu_axi_rlast; assign ifu_axi_bvalid = '0; assign ifu_axi_bresp = '0; assign ifu_axi_bid = {pt.IFU_BUS_TAG{1'b0}}; assign ifu_axi_arready = '0; assign ifu_axi_rvalid = '0; assign ifu_axi_rid = {pt.IFU_BUS_TAG{1'b0}}; assign ifu_axi_rdata = 0; assign ifu_axi_rresp = '0; assign ifu_axi_rlast = '0; //-------------------------- SB AXI signals-------------------------- // AXI Write Channels wire sb_axi_awvalid; wire sb_axi_awready; wire [pt.SB_BUS_TAG-1:0] sb_axi_awid; wire [31:0] sb_axi_awaddr; wire [3:0] sb_axi_awregion; wire [7:0] sb_axi_awlen; wire [2:0] sb_axi_awsize; wire [1:0] sb_axi_awburst; wire sb_axi_awlock; wire [3:0] sb_axi_awcache; wire [2:0] sb_axi_awprot; wire [3:0] sb_axi_awqos; wire sb_axi_wvalid; wire sb_axi_wready; wire [63:0] sb_axi_wdata; wire [7:0] sb_axi_wstrb; wire sb_axi_wlast; wire sb_axi_bvalid; wire sb_axi_bready; wire [1:0] sb_axi_bresp; wire [pt.SB_BUS_TAG-1:0] sb_axi_bid; // AXI Read Channels wire sb_axi_arvalid; wire sb_axi_arready; wire [pt.SB_BUS_TAG-1:0] sb_axi_arid; wire [31:0] sb_axi_araddr; wire [3:0] sb_axi_arregion; wire [7:0] sb_axi_arlen; wire [2:0] sb_axi_arsize; wire [1:0] sb_axi_arburst; wire sb_axi_arlock; wire [3:0] sb_axi_arcache; wire [2:0] sb_axi_arprot; wire [3:0] sb_axi_arqos; wire sb_axi_rvalid; wire sb_axi_rready; wire [pt.SB_BUS_TAG-1:0] sb_axi_rid; wire [63:0] sb_axi_rdata; wire [1:0] sb_axi_rresp; wire sb_axi_rlast; assign sb_axi_awready = '0; assign sb_axi_wready = '0; assign sb_axi_bvalid = '0; assign sb_axi_bresp = '0; assign sb_axi_bid = {pt.SB_BUS_TAG{1'b0}}; assign sb_axi_arready = '0; assign sb_axi_rvalid = '0; assign sb_axi_rid = {pt.SB_BUS_TAG{1'b0}}; assign sb_axi_rdata = '0; assign sb_axi_rresp = '0; assign sb_axi_rlast = '0; //-------------------------- DMA AXI signals-------------------------- // AXI Write Channels wire dma_axi_awvalid; wire dma_axi_awready; wire [pt.DMA_BUS_TAG-1:0] dma_axi_awid; wire [31:0] dma_axi_awaddr; wire [2:0] dma_axi_awsize; wire [2:0] dma_axi_awprot; wire [7:0] dma_axi_awlen; wire [1:0] dma_axi_awburst; wire dma_axi_wvalid; wire dma_axi_wready; wire [63:0] dma_axi_wdata; wire [7:0] dma_axi_wstrb; wire dma_axi_wlast; assign dma_axi_awvalid = 1'b0; assign dma_axi_awid = {pt.DMA_BUS_TAG{1'b0}}; assign dma_axi_awaddr = 32'd0; assign dma_axi_awsize = 3'd0; assign dma_axi_awprot = 3'd0; assign dma_axi_awlen = 8'd0; assign dma_axi_awburst = 2'd0; assign dma_axi_wvalid = 1'b0; assign dma_axi_wdata = 64'd0; assign dma_axi_wstrb = 8'd0; assign dma_axi_wlast = 1'b0; wire dma_axi_bvalid; wire dma_axi_bready; wire [1:0] dma_axi_bresp; wire [pt.DMA_BUS_TAG-1:0] dma_axi_bid; assign dma_axi_bready = 1'b0; // AXI Read Channels wire dma_axi_arvalid; wire dma_axi_arready; wire [pt.DMA_BUS_TAG-1:0] dma_axi_arid; wire [31:0] dma_axi_araddr; wire [2:0] dma_axi_arsize; wire [2:0] dma_axi_arprot; wire [7:0] dma_axi_arlen; wire [1:0] dma_axi_arburst; assign dma_axi_arvalid = 1'b0; assign dma_axi_arid = {pt.DMA_BUS_TAG{1'b0}}; assign dma_axi_araddr = 32'd0; assign dma_axi_arsize = 3'd0; assign dma_axi_arprot = 3'd0; assign dma_axi_arlen = 8'd0; assign dma_axi_arburst = 2'd0; wire dma_axi_rvalid; wire dma_axi_rready; wire [pt.DMA_BUS_TAG-1:0] dma_axi_rid; wire [63:0] dma_axi_rdata; wire [1:0] dma_axi_rresp; wire dma_axi_rlast; assign dma_axi_rready = 1'b0; // AXI assign ifu_axi_awready = 1'b1; assign ifu_axi_wready = 1'b1; assign ifu_axi_bvalid = '0; assign ifu_axi_bresp[1:0] = '0; assign ifu_axi_bid[pt.IFU_BUS_TAG-1:0] = '0; /*pragma coverage on*/ `endif // `ifdef RV_BUILD_AHB_LITE // DMI (core) logic dmi_en; logic [6:0] dmi_addr; logic dmi_wr_en; logic [31:0] dmi_wdata; logic [31:0] dmi_rdata; // DMI (core) logic dmi_reg_en; logic [6:0] dmi_reg_addr; logic dmi_reg_wr_en; logic [31:0] dmi_reg_wdata; logic [31:0] dmi_reg_rdata; `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_regfile_if regfile (); `endif // Instantiate the el2_veer core el2_veer #(.pt(pt)) veer ( .clk(clk), `ifdef RV_LOCKSTEP_REGFILE_ENABLE .regfile(regfile.veer_rf_src), `endif .* ); `ifdef RV_LOCKSTEP_ENABLE initial begin $display("Dual Core Lockstep enabled!\n"); end el2_veer_lockstep #(.pt(pt)) lockstep ( .clk(clk), `ifdef RV_LOCKSTEP_REGFILE_ENABLE .main_core_regfile(regfile.veer_rf_sink), `endif // `ifdef RV_LOCKSTEP_REGFILE_ENABLE .* ); `endif // `ifdef RV_LOCKSTEP_ENABLE // Instantiate the mem el2_mem #(.pt(pt)) mem ( .clk(active_l2clk), .rst_l(core_rst_l), .mem_export(el2_mem_export), .icache_export(el2_icache_export), .* ); logic unused_dmi_hard_reset; // JTAG/DMI instance dmi_wrapper dmi_wrapper ( // JTAG signals .trst_n (jtag_trst_n), // JTAG reset .tck (jtag_tck), // JTAG clock .tms (jtag_tms), // Test mode select .tdi (jtag_tdi), // Test Data Input .tdo (jtag_tdo), // Test Data Output .tdoEnable (jtag_tdoEn), // Test Data Output enable // Processor Signals .core_rst_n (dbg_rst_l), // Debug reset, active low .core_clk (clk), // Core clock .jtag_id (jtag_id), // JTAG ID .rd_data (dmi_rdata), // Read data from Processor .reg_wr_data (dmi_wdata), // Write data to Processor .reg_wr_addr (dmi_addr), // Write address to Processor .reg_en (dmi_en), // Write interface bit to Processor .reg_wr_en (dmi_wr_en), // Write enable to Processor .dmi_hard_reset (unused_dmi_hard_reset) ); // DMI core/uncore mux dmi_mux dmi_mux ( .core_enable (dmi_core_enable), .uncore_enable (dmi_uncore_enable), .dmi_en (dmi_en), .dmi_wr_en (dmi_wr_en), .dmi_addr (dmi_addr), .dmi_wdata (dmi_wdata), .dmi_rdata (dmi_rdata), .dmi_core_en (dmi_reg_en), .dmi_core_wr_en (dmi_reg_wr_en), .dmi_core_addr (dmi_reg_addr), .dmi_core_wdata (dmi_reg_wdata), .dmi_core_rdata (dmi_reg_rdata), .dmi_uncore_en (dmi_uncore_en), .dmi_uncore_wr_en (dmi_uncore_wr_en), .dmi_uncore_addr (dmi_uncore_addr), .dmi_uncore_wdata (dmi_uncore_wdata), .dmi_uncore_rdata (dmi_uncore_rdata) ); always_comb dmi_active = dmi_en; `ifdef RV_ASSERT_ON // to avoid internal assertions failure at time 0 initial begin $assertoff(0, veer); @(negedge clk) $asserton(0, veer); end `endif endmodule ================================================ FILE: design/exu/el2_exu.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_exu import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan control /*pragma coverage on*/ input logic [1:0] dec_data_en, // Clock enable {x,r}, one cycle pulse input logic [1:0] dec_ctl_en, // Clock enable {x,r}, two cycle pulse input logic [31:0] dbg_cmd_wrdata, // Debug data to primary I0 RS1 input el2_alu_pkt_t i0_ap, // DEC alu {valid,predecodes} input logic dec_debug_wdata_rs1_d, // Debug select to primary I0 RS1 input el2_predict_pkt_t dec_i0_predict_p_d, // DEC branch predict packet input logic [pt.BHT_GHR_SIZE-1:0] i0_predict_fghr_d, // DEC predict fghr input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] i0_predict_index_d, // DEC predict index input logic [pt.BTB_BTAG_SIZE-1:0] i0_predict_btag_d, // DEC predict branch tag input logic [31:0] lsu_result_m, // Load result M-stage input logic [31:0] lsu_nonblock_load_data, // nonblock load data input logic dec_i0_rs1_en_d, // Qualify GPR RS1 data input logic dec_i0_rs2_en_d, // Qualify GPR RS2 data input logic [31:0] gpr_i0_rs1_d, // DEC data gpr input logic [31:0] gpr_i0_rs2_d, // DEC data gpr input logic [31:0] dec_i0_immed_d, // DEC data immediate input logic [31:0] dec_i0_result_r, // DEC result in R-stage input logic [12:1] dec_i0_br_immed_d, // Branch immediate input logic dec_i0_alu_decode_d, // Valid to X-stage ALU input logic dec_i0_branch_d, // Branch in D-stage input logic dec_i0_select_pc_d, // PC select to RS1 input logic [31:1] dec_i0_pc_d, // Instruction PC input logic [3:0] dec_i0_rs1_bypass_en_d, // DEC bypass select 1 - X-stage, 0 - dec bypass data input logic [3:0] dec_i0_rs2_bypass_en_d, // DEC bypass select 1 - X-stage, 0 - dec bypass data input logic dec_csr_ren_d, // CSR read select input logic [31:0] dec_csr_rddata_d, // CSR read data input logic dec_qual_lsu_d, // LSU instruction at D. Use to quiet LSU operands input el2_mul_pkt_t mul_p, // DEC {valid, operand signs, low, operand bypass} input el2_div_pkt_t div_p, // DEC {valid, unsigned, rem} input logic dec_div_cancel, // Cancel the divide operation input logic [31:1] pred_correct_npc_x, // DEC NPC for correctly predicted branch input logic dec_tlu_flush_lower_r, // Flush divide and secondary ALUs input logic [31:1] dec_tlu_flush_path_r, // Redirect target input logic dec_extint_stall, // External stall mux select input logic [31:2] dec_tlu_meihap, // External stall mux data output logic [31:0] exu_lsu_rs1_d, // LSU operand output logic [31:0] exu_lsu_rs2_d, // LSU operand output logic exu_flush_final, // Pipe is being flushed this cycle output logic [31:1] exu_flush_path_final, // Target for the oldest flush source output logic [31:0] exu_i0_result_x, // Primary ALU result to DEC output logic [31:1] exu_i0_pc_x, // Primary PC result to DEC output logic [31:0] exu_csr_rs1_x, // RS1 source for a CSR instruction output logic [31:1] exu_npc_r, // Divide NPC output logic [1:0] exu_i0_br_hist_r, // to DEC I0 branch history output logic exu_i0_br_error_r, // to DEC I0 branch error output logic exu_i0_br_start_error_r, // to DEC I0 branch start error output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_i0_br_index_r, // to DEC I0 branch index output logic exu_i0_br_valid_r, // to DEC I0 branch valid output logic exu_i0_br_mp_r, // to DEC I0 branch mispredict output logic exu_i0_br_middle_r, // to DEC I0 branch middle output logic [pt.BHT_GHR_SIZE-1:0] exu_i0_br_fghr_r, // to DEC I0 branch fghr output logic exu_i0_br_way_r, // to DEC I0 branch way output el2_predict_pkt_t exu_mp_pkt, // Mispredict branch packet output logic [pt.BHT_GHR_SIZE-1:0] exu_mp_eghr, // Mispredict global history output logic [pt.BHT_GHR_SIZE-1:0] exu_mp_fghr, // Mispredict fghr output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_mp_index, // Mispredict index output logic [pt.BTB_BTAG_SIZE-1:0] exu_mp_btag, // Mispredict btag output logic exu_pmu_i0_br_misp, // to PMU - I0 E4 branch mispredict output logic exu_pmu_i0_br_ataken, // to PMU - I0 E4 taken output logic exu_pmu_i0_pc4, // to PMU - I0 E4 PC output logic [31:0] exu_div_result, // Divide result output logic exu_div_wren // Divide write enable to GPR ); logic [31:0] i0_rs1_bypass_data_d; logic [31:0] i0_rs2_bypass_data_d; logic i0_rs1_bypass_en_d; logic i0_rs2_bypass_en_d; logic [31:0] i0_rs1_d, i0_rs2_d; logic [31:0] muldiv_rs1_d; logic [31:1] pred_correct_npc_r; logic i0_pred_correct_upper_r; logic [31:1] i0_flush_path_upper_r; logic x_data_en, x_data_en_q1, x_data_en_q2, r_data_en, r_data_en_q2; logic x_ctl_en, r_ctl_en; logic [pt.BHT_GHR_SIZE-1:0] ghr_d_ns, ghr_d; logic [pt.BHT_GHR_SIZE-1:0] ghr_x_ns, ghr_x; logic i0_taken_d; logic i0_taken_x; logic i0_valid_d; logic i0_valid_x; logic [pt.BHT_GHR_SIZE-1:0] after_flush_eghr; el2_predict_pkt_t final_predict_mp; el2_predict_pkt_t i0_predict_newp_d; logic flush_in_d; logic [31:0] alu_result_x; logic mul_valid_x; logic [31:0] mul_result_x; el2_predict_pkt_t i0_pp_r; logic i0_flush_upper_d; logic [31:1] i0_flush_path_d; el2_predict_pkt_t i0_predict_p_d; logic i0_pred_correct_upper_d; logic i0_flush_upper_x; logic [31:1] i0_flush_path_x; el2_predict_pkt_t i0_predict_p_x; logic i0_pred_correct_upper_x; logic i0_branch_x; localparam PREDPIPESIZE = pt.BTB_ADDR_HI-pt.BTB_ADDR_LO+1+pt.BHT_GHR_SIZE+pt.BTB_BTAG_SIZE; logic [PREDPIPESIZE-1:0] predpipe_d, predpipe_x, predpipe_r, final_predpipe_mp; rvdffpcie #(31) i_flush_path_x_ff (.*, .clk(clk), .en ( x_data_en ), .din ( i0_flush_path_d[31:1] ), .dout( i0_flush_path_x[31:1] ) ); rvdffe #(32) i_csr_rs1_x_ff (.*, .clk(clk), .en ( x_data_en_q1 ), .din ( i0_rs1_d[31:0] ), .dout( exu_csr_rs1_x[31:0] ) ); rvdffppe #($bits(el2_predict_pkt_t)) i_predictpacket_x_ff (.*, .clk(clk), .en ( x_data_en ), .din ( i0_predict_p_d ), .dout( i0_predict_p_x ) ); rvdffe #(PREDPIPESIZE) i_predpipe_x_ff (.*, .clk(clk), .en ( x_data_en_q2 ), .din ( predpipe_d ), .dout( predpipe_x ) ); rvdffe #(PREDPIPESIZE) i_predpipe_r_ff (.*, .clk(clk), .en ( r_data_en_q2 ), .din ( predpipe_x ), .dout( predpipe_r ) ); rvdffe #(4+pt.BHT_GHR_SIZE) i_x_ff (.*, .clk(clk), .en ( x_ctl_en ), .din ({i0_valid_d,i0_taken_d,i0_flush_upper_d,i0_pred_correct_upper_d,ghr_x_ns[pt.BHT_GHR_SIZE-1:0]} ), .dout({i0_valid_x,i0_taken_x,i0_flush_upper_x,i0_pred_correct_upper_x,ghr_x[pt.BHT_GHR_SIZE-1:0]} ) ); rvdffppe #($bits(el2_predict_pkt_t)+1) i_r_ff0 (.*, .clk(clk), .en ( r_ctl_en ), .din ({i0_pred_correct_upper_x, i0_predict_p_x}), .dout({i0_pred_correct_upper_r, i0_pp_r }) ); rvdffpcie #(31) i_flush_r_ff (.*, .clk(clk), .en ( r_data_en ), .din ( i0_flush_path_x[31:1] ), .dout( i0_flush_path_upper_r[31:1]) ); rvdffpcie #(31) i_npc_r_ff (.*, .clk(clk), .en ( r_data_en ), .din ( pred_correct_npc_x[31:1] ), .dout( pred_correct_npc_r[31:1] ) ); rvdffie #(pt.BHT_GHR_SIZE+2,1) i_misc_ff (.*, .clk(clk), .din ({ghr_d_ns[pt.BHT_GHR_SIZE-1:0], mul_p.valid, dec_i0_branch_d}), .dout({ghr_d[pt.BHT_GHR_SIZE-1:0] , mul_valid_x, i0_branch_x}) ); assign predpipe_d[PREDPIPESIZE-1:0] = {i0_predict_fghr_d, i0_predict_index_d, i0_predict_btag_d}; assign i0_rs1_bypass_en_d = dec_i0_rs1_bypass_en_d[0] | dec_i0_rs1_bypass_en_d[1] | dec_i0_rs1_bypass_en_d[2] | dec_i0_rs1_bypass_en_d[3]; assign i0_rs2_bypass_en_d = dec_i0_rs2_bypass_en_d[0] | dec_i0_rs2_bypass_en_d[1] | dec_i0_rs2_bypass_en_d[2] | dec_i0_rs2_bypass_en_d[3]; assign i0_rs1_bypass_data_d[31:0]=({32{dec_i0_rs1_bypass_en_d[0]}} & dec_i0_result_r[31:0] ) | ({32{dec_i0_rs1_bypass_en_d[1]}} & lsu_result_m[31:0] ) | ({32{dec_i0_rs1_bypass_en_d[2]}} & exu_i0_result_x[31:0] ) | ({32{dec_i0_rs1_bypass_en_d[3]}} & lsu_nonblock_load_data[31:0]); assign i0_rs2_bypass_data_d[31:0]=({32{dec_i0_rs2_bypass_en_d[0]}} & dec_i0_result_r[31:0] ) | ({32{dec_i0_rs2_bypass_en_d[1]}} & lsu_result_m[31:0] ) | ({32{dec_i0_rs2_bypass_en_d[2]}} & exu_i0_result_x[31:0] ) | ({32{dec_i0_rs2_bypass_en_d[3]}} & lsu_nonblock_load_data[31:0]); assign i0_rs1_d[31:0] = ({32{ i0_rs1_bypass_en_d }} & i0_rs1_bypass_data_d[31:0]) | ({32{~i0_rs1_bypass_en_d & dec_i0_select_pc_d }} & {dec_i0_pc_d[31:1],1'b0} ) | // for jal's ({32{~i0_rs1_bypass_en_d & dec_debug_wdata_rs1_d }} & dbg_cmd_wrdata[31:0] ) | ({32{~i0_rs1_bypass_en_d & ~dec_debug_wdata_rs1_d & dec_i0_rs1_en_d}} & gpr_i0_rs1_d[31:0] ); assign i0_rs2_d[31:0] = ({32{~i0_rs2_bypass_en_d & dec_i0_rs2_en_d}} & gpr_i0_rs2_d[31:0] ) | ({32{~i0_rs2_bypass_en_d }} & dec_i0_immed_d[31:0] ) | ({32{ i0_rs2_bypass_en_d }} & i0_rs2_bypass_data_d[31:0]); assign exu_lsu_rs1_d[31:0] = ({32{~i0_rs1_bypass_en_d & ~dec_extint_stall & dec_i0_rs1_en_d & dec_qual_lsu_d}} & gpr_i0_rs1_d[31:0] ) | ({32{ i0_rs1_bypass_en_d & ~dec_extint_stall & dec_qual_lsu_d}} & i0_rs1_bypass_data_d[31:0]) | ({32{ dec_extint_stall & dec_qual_lsu_d}} & {dec_tlu_meihap[31:2],2'b0}); assign exu_lsu_rs2_d[31:0] = ({32{~i0_rs2_bypass_en_d & ~dec_extint_stall & dec_i0_rs2_en_d & dec_qual_lsu_d}} & gpr_i0_rs2_d[31:0] ) | ({32{ i0_rs2_bypass_en_d & ~dec_extint_stall & dec_qual_lsu_d}} & i0_rs2_bypass_data_d[31:0]); assign muldiv_rs1_d[31:0] = ({32{~i0_rs1_bypass_en_d & dec_i0_rs1_en_d}} & gpr_i0_rs1_d[31:0] ) | ({32{ i0_rs1_bypass_en_d }} & i0_rs1_bypass_data_d[31:0]); assign x_data_en = dec_data_en[1]; assign x_data_en_q1 = dec_data_en[1] & dec_csr_ren_d; assign x_data_en_q2 = dec_data_en[1] & dec_i0_branch_d; assign r_data_en = dec_data_en[0]; assign r_data_en_q2 = dec_data_en[0] & i0_branch_x; assign x_ctl_en = dec_ctl_en[1]; assign r_ctl_en = dec_ctl_en[0]; el2_exu_alu_ctl #(.pt(pt)) i_alu (.*, .enable ( x_data_en ), // I .pp_in ( i0_predict_newp_d ), // I .valid_in ( dec_i0_alu_decode_d ), // I .flush_upper_x ( i0_flush_upper_x ), // I .flush_lower_r ( dec_tlu_flush_lower_r ), // I .a_in ( i0_rs1_d[31:0] ), // I .b_in ( i0_rs2_d[31:0] ), // I .pc_in ( dec_i0_pc_d[31:1] ), // I .brimm_in ( dec_i0_br_immed_d[12:1] ), // I .ap ( i0_ap ), // I .csr_ren_in ( dec_csr_ren_d ), // I .csr_rddata_in ( dec_csr_rddata_d[31:0] ), // I .result_ff ( alu_result_x[31:0] ), // O .flush_upper_out ( i0_flush_upper_d ), // O .flush_final_out ( exu_flush_final ), // O .flush_path_out ( i0_flush_path_d[31:1] ), // O .predict_p_out ( i0_predict_p_d ), // O .pred_correct_out ( i0_pred_correct_upper_d ), // O .pc_ff ( exu_i0_pc_x[31:1] )); // O el2_exu_mul_ctl #(.pt(pt)) i_mul (.*, .mul_p ( mul_p & {$bits(el2_mul_pkt_t){mul_p.valid}} ), // I .rs1_in ( muldiv_rs1_d[31:0] & {32{mul_p.valid}} ), // I .rs2_in ( i0_rs2_d[31:0] & {32{mul_p.valid}} ), // I .result_x ( mul_result_x[31:0] )); // O el2_exu_div_ctl #(.pt(pt)) i_div (.*, .cancel ( dec_div_cancel ), // I .dp ( div_p ), // I .dividend ( muldiv_rs1_d[31:0] ), // I .divisor ( i0_rs2_d[31:0] ), // I .finish_dly ( exu_div_wren ), // O .out ( exu_div_result[31:0] )); // O assign exu_i0_result_x[31:0] = (mul_valid_x) ? mul_result_x[31:0] : alu_result_x[31:0]; always_comb begin i0_predict_newp_d = dec_i0_predict_p_d; i0_predict_newp_d.boffset = dec_i0_pc_d[1]; // from the start of inst end assign exu_pmu_i0_br_misp = i0_pp_r.misp; assign exu_pmu_i0_br_ataken = i0_pp_r.ataken; assign exu_pmu_i0_pc4 = i0_pp_r.pc4; assign i0_valid_d = i0_predict_p_d.valid & dec_i0_alu_decode_d & ~dec_tlu_flush_lower_r; assign i0_taken_d = (i0_predict_p_d.ataken & dec_i0_alu_decode_d); if(pt.BTB_ENABLE==1) begin // maintain GHR at D assign ghr_d_ns[pt.BHT_GHR_SIZE-1:0] = ({pt.BHT_GHR_SIZE{~dec_tlu_flush_lower_r & i0_valid_d}} & {ghr_d[pt.BHT_GHR_SIZE-2:0], i0_taken_d}) | ({pt.BHT_GHR_SIZE{~dec_tlu_flush_lower_r & ~i0_valid_d}} & ghr_d[pt.BHT_GHR_SIZE-1:0] ) | ({pt.BHT_GHR_SIZE{ dec_tlu_flush_lower_r }} & ghr_x[pt.BHT_GHR_SIZE-1:0] ); // maintain GHR at X assign ghr_x_ns[pt.BHT_GHR_SIZE-1:0] = ({pt.BHT_GHR_SIZE{ i0_valid_x}} & {ghr_x[pt.BHT_GHR_SIZE-2:0], i0_taken_x}) | ({pt.BHT_GHR_SIZE{~i0_valid_x}} & ghr_x[pt.BHT_GHR_SIZE-1:0] ) ; assign exu_i0_br_valid_r = i0_pp_r.valid; assign exu_i0_br_mp_r = i0_pp_r.misp; assign exu_i0_br_way_r = i0_pp_r.way; assign exu_i0_br_hist_r[1:0] = {2{i0_pp_r.valid}} & i0_pp_r.hist[1:0]; assign exu_i0_br_error_r = i0_pp_r.br_error; assign exu_i0_br_middle_r = i0_pp_r.pc4 ^ i0_pp_r.boffset; assign exu_i0_br_start_error_r = i0_pp_r.br_start_error; assign {exu_i0_br_fghr_r[pt.BHT_GHR_SIZE-1:0], exu_i0_br_index_r[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]}= predpipe_r[PREDPIPESIZE-1:pt.BTB_BTAG_SIZE]; assign final_predict_mp = (i0_flush_upper_x) ? i0_predict_p_x : '0; assign final_predpipe_mp[PREDPIPESIZE-1:0] = (i0_flush_upper_x) ? predpipe_x : '0; assign after_flush_eghr[pt.BHT_GHR_SIZE-1:0] = (i0_flush_upper_x & ~dec_tlu_flush_lower_r) ? ghr_d[pt.BHT_GHR_SIZE-1:0] : ghr_x[pt.BHT_GHR_SIZE-1:0]; assign exu_mp_pkt.valid = final_predict_mp.valid; assign exu_mp_pkt.way = final_predict_mp.way; assign exu_mp_pkt.misp = final_predict_mp.misp; assign exu_mp_pkt.pcall = final_predict_mp.pcall; assign exu_mp_pkt.pja = final_predict_mp.pja; assign exu_mp_pkt.pret = final_predict_mp.pret; assign exu_mp_pkt.ataken = final_predict_mp.ataken; assign exu_mp_pkt.boffset = final_predict_mp.boffset; assign exu_mp_pkt.pc4 = final_predict_mp.pc4; assign exu_mp_pkt.hist[1:0] = final_predict_mp.hist[1:0]; assign exu_mp_pkt.toffset[11:0] = final_predict_mp.toffset[11:0]; assign exu_mp_pkt.br_error = '0; assign exu_mp_pkt.br_start_error = '0; assign exu_mp_fghr[pt.BHT_GHR_SIZE-1:0] = after_flush_eghr[pt.BHT_GHR_SIZE-1:0]; assign {exu_mp_index[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO], exu_mp_btag[pt.BTB_BTAG_SIZE-1:0]} = final_predpipe_mp[PREDPIPESIZE-pt.BHT_GHR_SIZE-1:0]; assign exu_mp_eghr[pt.BHT_GHR_SIZE-1:0] = final_predpipe_mp[PREDPIPESIZE-1:pt.BTB_ADDR_HI-pt.BTB_ADDR_LO+pt.BTB_BTAG_SIZE+1]; // mp ghr for bht write end // if (pt.BTB_ENABLE==1) else begin assign ghr_d_ns = '0; assign ghr_x_ns = '0; assign exu_mp_pkt = '0; assign exu_mp_eghr = '0; assign exu_mp_fghr = '0; assign exu_mp_index = '0; assign exu_mp_btag = '0; assign exu_i0_br_hist_r = '0; assign exu_i0_br_error_r = '0; assign exu_i0_br_start_error_r = '0; assign exu_i0_br_index_r = '0; assign exu_i0_br_valid_r = '0; assign exu_i0_br_mp_r = '0; assign exu_i0_br_middle_r = '0; assign exu_i0_br_fghr_r = '0; assign exu_i0_br_way_r = '0; end // else: !if(pt.BTB_ENABLE==1) assign exu_flush_path_final[31:1] = ( {31{ dec_tlu_flush_lower_r }} & dec_tlu_flush_path_r[31:1] ) | ( {31{~dec_tlu_flush_lower_r & i0_flush_upper_d}} & i0_flush_path_d[31:1] ); assign exu_npc_r[31:1] = (i0_pred_correct_upper_r) ? pred_correct_npc_r[31:1] : i0_flush_path_upper_r[31:1]; endmodule // el2_exu ================================================ FILE: design/exu/el2_exu_alu_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_exu_alu_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan control /*pragma coverage on*/ input logic flush_upper_x, // Branch flush from previous cycle input logic flush_lower_r, // Master flush of entire pipeline input logic enable, // Clock enable input logic valid_in, // Valid input el2_alu_pkt_t ap, // predecodes input logic csr_ren_in, // CSR select input logic [31:0] csr_rddata_in, // CSR data input logic signed [31:0] a_in, // A operand input logic [31:0] b_in, // B operand input logic [31:1] pc_in, // for pc=pc+2,4 calculations input el2_predict_pkt_t pp_in, // Predicted branch structure input logic [12:1] brimm_in, // Branch offset output logic [31:0] result_ff, // final result output logic flush_upper_out, // Branch flush output logic flush_final_out, // Branch flush or flush entire pipeline output logic [31:1] flush_path_out, // Branch flush PC output logic [31:1] pc_ff, // flopped PC output logic pred_correct_out, // NPC control output el2_predict_pkt_t predict_p_out // Predicted branch structure ); logic [31:0] zba_a_in; logic [31:0] aout; logic cout,ov,neg; logic [31:0] lout; logic [31:0] sout; logic sel_shift; logic sel_adder; logic slt_one; logic actual_taken; logic [31:1] pcout; logic cond_mispredict; logic target_mispredict; logic eq, ne, lt, ge; logic any_jal; logic [1:0] newhist; logic sel_pc; logic [31:0] csr_write_data; logic [31:0] result; // *** Start - BitManip *** // Zbb logic ap_clz; logic ap_ctz; logic ap_cpop; logic ap_sext_b; logic ap_sext_h; logic ap_min; logic ap_max; logic ap_rol; logic ap_ror; logic ap_rev8; logic ap_orc_b; logic ap_zbb; // Zbs logic ap_bset; logic ap_bclr; logic ap_binv; logic ap_bext; // Zbp logic ap_pack; logic ap_packu; logic ap_packh; // Zba logic ap_sh1add; logic ap_sh2add; logic ap_sh3add; logic ap_zba; if (pt.BITMANIP_ZBB == 1) begin assign ap_clz = ap.clz; assign ap_ctz = ap.ctz; assign ap_cpop = ap.cpop; assign ap_sext_b = ap.sext_b; assign ap_sext_h = ap.sext_h; assign ap_min = ap.min; assign ap_max = ap.max; end else begin assign ap_clz = 1'b0; assign ap_ctz = 1'b0; assign ap_cpop = 1'b0; assign ap_sext_b = 1'b0; assign ap_sext_h = 1'b0; assign ap_min = 1'b0; assign ap_max = 1'b0; end if ( (pt.BITMANIP_ZBB == 1) | (pt.BITMANIP_ZBP == 1) ) begin assign ap_rol = ap.rol; assign ap_ror = ap.ror; assign ap_rev8 = ap.grev & (b_in[4:0] == 5'b11000); assign ap_orc_b = ap.gorc & (b_in[4:0] == 5'b00111); assign ap_zbb = ap.zbb; end else begin assign ap_rol = 1'b0; assign ap_ror = 1'b0; assign ap_rev8 = 1'b0; assign ap_orc_b = 1'b0; assign ap_zbb = 1'b0; end if (pt.BITMANIP_ZBS == 1) begin assign ap_bset = ap.bset; assign ap_bclr = ap.bclr; assign ap_binv = ap.binv; assign ap_bext = ap.bext; end else begin assign ap_bset = 1'b0; assign ap_bclr = 1'b0; assign ap_binv = 1'b0; assign ap_bext = 1'b0; end if (pt.BITMANIP_ZBP == 1) begin assign ap_packu = ap.packu; end else begin assign ap_packu = 1'b0; end if ( (pt.BITMANIP_ZBB == 1) | (pt.BITMANIP_ZBP == 1) | (pt.BITMANIP_ZBE == 1) | (pt.BITMANIP_ZBF == 1) ) begin assign ap_pack = ap.pack; assign ap_packh = ap.packh; end else begin assign ap_pack = 1'b0; assign ap_packh = 1'b0; end if (pt.BITMANIP_ZBA == 1) begin assign ap_sh1add = ap.sh1add; assign ap_sh2add = ap.sh2add; assign ap_sh3add = ap.sh3add; assign ap_zba = ap.zba; end else begin assign ap_sh1add = 1'b0; assign ap_sh2add = 1'b0; assign ap_sh3add = 1'b0; assign ap_zba = 1'b0; end // *** End - BitManip *** rvdffpcie #(31) i_pc_ff (.*, .clk(clk), .en(enable), .din(pc_in[31:1]), .dout(pc_ff[31:1])); // any PC is run through here - doesn't have to be alu rvdffe #(32) i_result_ff (.*, .clk(clk), .en(enable & valid_in), .din(result[31:0]), .dout(result_ff[31:0])); // immediates are just muxed into rs2 // add => add=1; // sub => add=1; sub=1; // and => lctl=3 // or => lctl=2 // xor => lctl=1 // sll => sctl=3 // srl => sctl=2 // sra => sctl=1 // slt => slt // lui => lctl=2; or x0, imm20 previously << 12 // auipc => add; add pc, imm20 previously << 12 // beq => bctl=4; add; add x0, pc, sext(offset[12:1]) // bne => bctl=3; add; add x0, pc, sext(offset[12:1]) // blt => bctl=2; add; add x0, pc, sext(offset[12:1]) // bge => bctl=1; add; add x0, pc, sext(offset[12:1]) // jal => rs1=pc {pc[31:1],1'b0}, rs2=sext(offset20:1]); rd=pc+[2,4] // jalr => rs1=rs1, rs2=sext(offset20:1]); rd=pc+[2,4] assign zba_a_in[31:0] = ( {32{ ap_sh1add}} & {a_in[30:0],1'b0} ) | ( {32{ ap_sh2add}} & {a_in[29:0],2'b0} ) | ( {32{ ap_sh3add}} & {a_in[28:0],3'b0} ) | ( {32{~ap_zba }} & a_in[31:0] ); logic [31:0] bm; assign bm[31:0] = ( ap.sub ) ? ~b_in[31:0] : b_in[31:0]; assign {cout, aout[31:0]} = {1'b0, zba_a_in[31:0]} + {1'b0, bm[31:0]} + {32'b0, ap.sub}; assign ov = (~a_in[31] & ~bm[31] & aout[31]) | ( a_in[31] & bm[31] & ~aout[31] ); assign lt = (~ap.unsign & (neg ^ ov)) | ( ap.unsign & ~cout); assign eq = (a_in[31:0] == b_in[31:0]); assign ne = ~eq; assign neg = aout[31]; assign ge = ~lt; assign lout[31:0] = ( {32{csr_ren_in }} & csr_rddata_in[31:0] ) | ( {32{ap.land & ~ap_zbb}} & a_in[31:0] & b_in[31:0] ) | ( {32{ap.lor & ~ap_zbb}} & (a_in[31:0] | b_in[31:0]) ) | ( {32{ap.lxor & ~ap_zbb}} & (a_in[31:0] ^ b_in[31:0]) ) | ( {32{ap.land & ap_zbb}} & a_in[31:0] & ~b_in[31:0] ) | ( {32{ap.lor & ap_zbb}} & (a_in[31:0] | ~b_in[31:0]) ) | ( {32{ap.lxor & ap_zbb}} & (a_in[31:0] ^ ~b_in[31:0]) ); // * * * * * * * * * * * * * * * * * * BitManip : ROL,ROR * * * * * * * * * * * * * * * * * * // * * * * * * * * * * * * * * * * * * BitManip : ZBEXT * * * * * * * * * * * * * * * * * * logic [5:0] shift_amount; logic [31:0] shift_mask; logic [62:0] shift_extend; logic [62:0] shift_long; assign shift_amount[5:0] = ( { 6{ap.sll}} & (6'd32 - {1'b0,b_in[4:0]}) ) | // [5] unused ( { 6{ap.srl}} & {1'b0,b_in[4:0]} ) | ( { 6{ap.sra}} & {1'b0,b_in[4:0]} ) | ( { 6{ap_rol}} & (6'd32 - {1'b0,b_in[4:0]}) ) | ( { 6{ap_ror}} & {1'b0,b_in[4:0]} ) | ( { 6{ap_bext}} & {1'b0,b_in[4:0]} ); assign shift_mask[31:0] = ( 32'hffffffff << ({5{ap.sll}} & b_in[4:0]) ); assign shift_extend[31:0] = a_in[31:0]; assign shift_extend[62:32] = ( {31{ap.sra}} & {31{a_in[31]}} ) | ( {31{ap.sll}} & a_in[30:0] ) | ( {31{ap_rol}} & a_in[30:0] ) | ( {31{ap_ror}} & a_in[30:0] ); assign shift_long[62:0] = 63'( shift_extend[62:0] >> shift_amount[4:0] ); // 62-32 unused assign sout[31:0] = shift_long[31:0] & shift_mask[31:0]; // * * * * * * * * * * * * * * * * * * BitManip : CLZ,CTZ * * * * * * * * * * * * * * * * * * logic bitmanip_clz_ctz_sel; logic [31:0] bitmanip_a_reverse_ff; logic [31:0] bitmanip_lzd_in; logic [5:0] bitmanip_dw_lzd_enc; logic [5:0] bitmanip_clz_ctz_result; assign bitmanip_clz_ctz_sel = ap_clz | ap_ctz; assign bitmanip_a_reverse_ff[31:0] = {a_in[0], a_in[1], a_in[2], a_in[3], a_in[4], a_in[5], a_in[6], a_in[7], a_in[8], a_in[9], a_in[10], a_in[11], a_in[12], a_in[13], a_in[14], a_in[15], a_in[16], a_in[17], a_in[18], a_in[19], a_in[20], a_in[21], a_in[22], a_in[23], a_in[24], a_in[25], a_in[26], a_in[27], a_in[28], a_in[29], a_in[30], a_in[31]}; assign bitmanip_lzd_in[31:0] = ( {32{ap_clz}} & a_in[31:0] ) | ( {32{ap_ctz}} & bitmanip_a_reverse_ff[31:0]); logic [31:0] bitmanip_lzd_os; integer i; logic found; always_comb begin bitmanip_lzd_os[31:0] = bitmanip_lzd_in[31:0]; bitmanip_dw_lzd_enc[5:0]= 6'b0; found = 1'b0; for (int i=0; i<32; i++) begin if (bitmanip_lzd_os[31] == 1'b0 && found == 0) begin bitmanip_dw_lzd_enc[5:0]= bitmanip_dw_lzd_enc[5:0] + 6'b00_0001; bitmanip_lzd_os[31:0] = bitmanip_lzd_os[31:0] << 1; end else found=1'b1; end end assign bitmanip_clz_ctz_result[5:0] = {6{bitmanip_clz_ctz_sel}} & {bitmanip_dw_lzd_enc[5],( {5{~bitmanip_dw_lzd_enc[5]}} & bitmanip_dw_lzd_enc[4:0] )}; // * * * * * * * * * * * * * * * * * * BitManip : CPOP * * * * * * * * * * * * * * * * * * logic [5:0] bitmanip_cpop; logic [5:0] bitmanip_cpop_result; integer bitmanip_cpop_i; always_comb begin bitmanip_cpop[5:0] = 6'b0; for (bitmanip_cpop_i=0; bitmanip_cpop_i<32; bitmanip_cpop_i++) begin bitmanip_cpop[5:0] = bitmanip_cpop[5:0] + {5'b0,a_in[bitmanip_cpop_i]}; end // FOR bitmanip_cpop_i end // ALWAYS_COMB assign bitmanip_cpop_result[5:0] = {6{ap_cpop}} & bitmanip_cpop[5:0]; // * * * * * * * * * * * * * * * * * * BitManip : SEXT_B,SEXT_H * * * * * * * * * * * * * * * * * logic [31:0] bitmanip_sext_result; assign bitmanip_sext_result[31:0] = ( {32{ap_sext_b}} & { {24{a_in[7]}} ,a_in[7:0] } ) | ( {32{ap_sext_h}} & { {16{a_in[15]}},a_in[15:0] } ); // * * * * * * * * * * * * * * * * * * BitManip : MIN,MAX,MINU,MAXU * * * * * * * * * * * * * * * logic bitmanip_minmax_sel; logic [31:0] bitmanip_minmax_result; assign bitmanip_minmax_sel = ap_min | ap_max; logic bitmanip_minmax_sel_a; assign bitmanip_minmax_sel_a = ge ^ ap_min; assign bitmanip_minmax_result[31:0] = ({32{bitmanip_minmax_sel & bitmanip_minmax_sel_a}} & a_in[31:0]) | ({32{bitmanip_minmax_sel & ~bitmanip_minmax_sel_a}} & b_in[31:0]); // * * * * * * * * * * * * * * * * * * BitManip : PACK, PACKU, PACKH * * * * * * * * * * * * * * * logic [31:0] bitmanip_pack_result; logic [31:0] bitmanip_packu_result; logic [31:0] bitmanip_packh_result; assign bitmanip_pack_result[31:0] = {32{ap_pack}} & {b_in[15:0], a_in[15:0]}; assign bitmanip_packu_result[31:0] = {32{ap_packu}} & {b_in[31:16],a_in[31:16]}; assign bitmanip_packh_result[31:0] = {32{ap_packh}} & {16'b0,b_in[7:0],a_in[7:0]}; // * * * * * * * * * * * * * * * * * * BitManip : REV, ORC_B * * * * * * * * * * * * * * * * * * logic [31:0] bitmanip_rev8_result; logic [31:0] bitmanip_orc_b_result; assign bitmanip_rev8_result[31:0] = {32{ap_rev8}} & {a_in[7:0],a_in[15:8],a_in[23:16],a_in[31:24]}; // uint32_t gorc32(uint32_t rs1, uint32_t rs2) // { // uint32_t x = rs1; // int shamt = rs2 & 31; ORC.B ORC16 // if (shamt & 1) x |= ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1); 1 0 // if (shamt & 2) x |= ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2); 1 0 // if (shamt & 4) x |= ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4); 1 0 // if (shamt & 8) x |= ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8); 0 0 // if (shamt & 16) x |= ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16); 0 1 // return x; // } // BEFORE 31 , 30 , 29 , 28 , 27 , 26, 25, 24 // shamt[0] b = a31|a30,a31|a30,a29|a28,a29|a28, a27|a26,a27|a26,a25|a24,a25|a24 // shamt[1] c = b31|b29,b30|b28,b31|b29,b30|b28, b27|b25,b26|b24,b27|b25,b26|b24 // shamt[2] d = c31|c27,c30|c26,c29|c25,c28|c24, c31|c27,c30|c26,c29|c25,c28|c24 // // Expand d31 = c31 | c27; // = b31 | b29 | b27 | b25; // = a31|a30 | a29|a28 | a27|a26 | a25|a24 assign bitmanip_orc_b_result[31:0] = {32{ap_orc_b}} & { {8{| a_in[31:24]}}, {8{| a_in[23:16]}}, {8{| a_in[15:8]}}, {8{| a_in[7:0]}} }; // * * * * * * * * * * * * * * * * * * BitManip : ZBSET, ZBCLR, ZBINV * * * * * * * * * * * * * * logic [31:0] bitmanip_sb_1hot; logic [31:0] bitmanip_sb_data; assign bitmanip_sb_1hot[31:0] = ( 32'h00000001 << b_in[4:0] ); assign bitmanip_sb_data[31:0] = ( {32{ap_bset}} & ( a_in[31:0] | bitmanip_sb_1hot[31:0]) ) | ( {32{ap_bclr}} & ( a_in[31:0] & ~bitmanip_sb_1hot[31:0]) ) | ( {32{ap_binv}} & ( a_in[31:0] ^ bitmanip_sb_1hot[31:0]) ); assign sel_shift = ap.sll | ap.srl | ap.sra | ap_rol | ap_ror; assign sel_adder = (ap.add | ap.sub | ap_zba) & ~ap.slt & ~ap_min & ~ap_max; assign sel_pc = ap.jal | pp_in.pcall | pp_in.pja | pp_in.pret; assign csr_write_data[31:0]= (ap.csr_imm) ? b_in[31:0] : a_in[31:0]; assign slt_one = ap.slt & lt; assign result[31:0] = lout[31:0] | ({32{sel_shift}} & sout[31:0] ) | ({32{sel_adder}} & aout[31:0] ) | ({32{sel_pc}} & {pcout[31:1],1'b0} ) | ({32{ap.csr_write}} & csr_write_data[31:0] ) | {31'b0, slt_one} | ({32{ap_bext}} & {31'b0, sout[0]} ) | {26'b0, bitmanip_clz_ctz_result[5:0]} | {26'b0, bitmanip_cpop_result[5:0]} | bitmanip_sext_result[31:0] | bitmanip_minmax_result[31:0] | bitmanip_pack_result[31:0] | bitmanip_packu_result[31:0] | bitmanip_packh_result[31:0] | bitmanip_rev8_result[31:0] | bitmanip_orc_b_result[31:0] | bitmanip_sb_data[31:0]; // *** branch handling *** assign any_jal = ap.jal | pp_in.pcall | pp_in.pja | pp_in.pret; assign actual_taken = (ap.beq & eq) | (ap.bne & ne) | (ap.blt & lt) | (ap.bge & ge) | any_jal; // for a conditional br pcout[] will be the opposite of the branch prediction // for jal or pcall, it will be the link address pc+2 or pc+4 rvbradder ibradder ( .pc ( pc_in[31:1] ), .offset ( brimm_in[12:1] ), .dout ( pcout[31:1] )); // pred_correct is for the npc logic // pred_correct indicates not to use the flush_path // for any_jal pred_correct==0 assign pred_correct_out = (valid_in & ap.predict_nt & ~actual_taken & ~any_jal) | (valid_in & ap.predict_t & actual_taken & ~any_jal); // for any_jal adder output is the flush path assign flush_path_out[31:1]= (any_jal) ? aout[31:1] : pcout[31:1]; // pcall and pret are included here assign cond_mispredict = (ap.predict_t & ~actual_taken) | (ap.predict_nt & actual_taken); // target mispredicts on ret's assign target_mispredict = pp_in.pret & (pp_in.prett[31:1] != aout[31:1]); assign flush_upper_out = (ap.jal | cond_mispredict | target_mispredict) & valid_in & ~flush_upper_x & ~flush_lower_r; assign flush_final_out = ( (ap.jal | cond_mispredict | target_mispredict) & valid_in & ~flush_upper_x ) | flush_lower_r; // .i 3 // .o 2 // .ilb hist[1] hist[0] taken // .ob newhist[1] newhist[0] // .type fd // // 00 0 01 // 01 0 01 // 10 0 00 // 11 0 10 // 00 1 10 // 01 1 00 // 10 1 11 // 11 1 11 assign newhist[1] = ( pp_in.hist[1] & pp_in.hist[0]) | (~pp_in.hist[0] & actual_taken); assign newhist[0] = (~pp_in.hist[1] & ~actual_taken) | ( pp_in.hist[1] & actual_taken); always_comb begin predict_p_out = pp_in; predict_p_out.misp = ~flush_upper_x & ~flush_lower_r & (cond_mispredict | target_mispredict); predict_p_out.ataken = actual_taken; predict_p_out.hist[1] = newhist[1]; predict_p_out.hist[0] = newhist[0]; end endmodule // el2_exu_alu_ctl ================================================ FILE: design/exu/el2_exu_div_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_exu_div_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan mode /*pragma coverage on*/ input el2_div_pkt_t dp, // valid, sign, rem input logic [31:0] dividend, // Numerator input logic [31:0] divisor, // Denominator input logic cancel, // Cancel divide output logic finish_dly, // Finish to match data output logic [31:0] out // Result ); logic [31:0] out_raw; assign out[31:0] = {32{finish_dly}} & out_raw[31:0]; // Qualification added to quiet result bus while divide is iterating if (pt.DIV_NEW == 0) begin : genblock1 el2_exu_div_existing_1bit_cheapshortq i_existing_1bit_div_cheapshortq ( .clk ( clk ), // I .rst_l ( rst_l ), // I .scan_mode ( scan_mode ), // I .cancel ( cancel ), // I .valid_in ( dp.valid ), // I .signed_in (~dp.unsign ), // I .rem_in ( dp.rem ), // I .dividend_in ( dividend[31:0] ), // I .divisor_in ( divisor[31:0] ), // I .valid_out ( finish_dly ), // O .data_out ( out_raw[31:0] )); // O end if ( (pt.DIV_NEW == 1) & (pt.DIV_BIT == 1) ) begin : genblock2 el2_exu_div_new_1bit_fullshortq i_new_1bit_div_fullshortq ( .clk ( clk ), // I .rst_l ( rst_l ), // I .scan_mode ( scan_mode ), // I .cancel ( cancel ), // I .valid_in ( dp.valid ), // I .signed_in (~dp.unsign ), // I .rem_in ( dp.rem ), // I .dividend_in ( dividend[31:0] ), // I .divisor_in ( divisor[31:0] ), // I .valid_out ( finish_dly ), // O .data_out ( out_raw[31:0] )); // O end if ( (pt.DIV_NEW == 1) & (pt.DIV_BIT == 2) ) begin : genblock3 el2_exu_div_new_2bit_fullshortq i_new_2bit_div_fullshortq ( .clk ( clk ), // I .rst_l ( rst_l ), // I .scan_mode ( scan_mode ), // I .cancel ( cancel ), // I .valid_in ( dp.valid ), // I .signed_in (~dp.unsign ), // I .rem_in ( dp.rem ), // I .dividend_in ( dividend[31:0] ), // I .divisor_in ( divisor[31:0] ), // I .valid_out ( finish_dly ), // O .data_out ( out_raw[31:0] )); // O end if ( (pt.DIV_NEW == 1) & (pt.DIV_BIT == 3) ) begin : genblock4 el2_exu_div_new_3bit_fullshortq i_new_3bit_div_fullshortq ( .clk ( clk ), // I .rst_l ( rst_l ), // I .scan_mode ( scan_mode ), // I .cancel ( cancel ), // I .valid_in ( dp.valid ), // I .signed_in (~dp.unsign ), // I .rem_in ( dp.rem ), // I .dividend_in ( dividend[31:0] ), // I .divisor_in ( divisor[31:0] ), // I .valid_out ( finish_dly ), // O .data_out ( out_raw[31:0] )); // O end if ( (pt.DIV_NEW == 1) & (pt.DIV_BIT == 4) ) begin : genblock5 el2_exu_div_new_4bit_fullshortq i_new_4bit_div_fullshortq ( .clk ( clk ), // I .rst_l ( rst_l ), // I .scan_mode ( scan_mode ), // I .cancel ( cancel ), // I .valid_in ( dp.valid ), // I .signed_in (~dp.unsign ), // I .rem_in ( dp.rem ), // I .dividend_in ( dividend[31:0] ), // I .divisor_in ( divisor[31:0] ), // I .valid_out ( finish_dly ), // O .data_out ( out_raw[31:0] )); // O end endmodule // el2_exu_div_ctl // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * module el2_exu_div_existing_1bit_cheapshortq ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan mode /*pragma coverage on*/ input logic cancel, // Flush pipeline input logic valid_in, input logic signed_in, input logic rem_in, input logic [31:0] dividend_in, input logic [31:0] divisor_in, output logic valid_out, output logic [31:0] data_out ); logic div_clken; logic run_in, run_state; logic [5:0] count_in, count; logic [32:0] m_ff; logic qff_enable; logic aff_enable; logic [32:0] q_in, q_ff; logic [32:0] a_in, a_ff; logic [32:0] m_eff; logic [32:0] a_shift; logic dividend_neg_ff, divisor_neg_ff; logic [31:0] dividend_comp; logic [31:0] dividend_eff; logic [31:0] q_ff_comp; logic [31:0] q_ff_eff; logic [31:0] a_ff_comp; logic [31:0] a_ff_eff; logic sign_ff, sign_eff; logic rem_ff; logic add; logic [32:0] a_eff; logic [64:0] a_eff_shift; logic rem_correct; logic valid_ff_x; logic valid_x; logic finish; logic finish_ff; logic smallnum_case, smallnum_case_ff; logic [3:0] smallnum, smallnum_ff; logic m_already_comp; logic [4:0] a_cls; logic [4:0] b_cls; logic [5:0] shortq_shift; logic [5:0] shortq_shift_ff; logic [5:0] shortq; logic shortq_enable; logic shortq_enable_ff; logic [32:0] short_dividend; logic [3:0] shortq_raw; logic [3:0] shortq_shift_xx; rvdffe #(23) i_misc_ff (.*, .clk(clk), .en(div_clken), .din ({valid_in & ~cancel, finish & ~cancel, run_in, count_in[5:0], (valid_in & dividend_in[31]) | (~valid_in & dividend_neg_ff), (valid_in & divisor_in[31] ) | (~valid_in & divisor_neg_ff ), (valid_in & sign_eff ) | (~valid_in & sign_ff ), (valid_in & rem_in ) | (~valid_in & rem_ff ), smallnum_case, smallnum[3:0], shortq_enable, shortq_shift[3:0]}), .dout({valid_ff_x, finish_ff, run_state, count[5:0], dividend_neg_ff, divisor_neg_ff, sign_ff, rem_ff, smallnum_case_ff, smallnum_ff[3:0], shortq_enable_ff, shortq_shift_xx[3:0]})); rvdffe #(33) mff (.*, .clk(clk), .en(valid_in), .din({signed_in & divisor_in[31], divisor_in[31:0]}), .dout(m_ff[32:0])); rvdffe #(33) qff (.*, .clk(clk), .en(qff_enable), .din(q_in[32:0]), .dout(q_ff[32:0])); rvdffe #(33) aff (.*, .clk(clk), .en(aff_enable), .din(a_in[32:0]), .dout(a_ff[32:0])); rvtwoscomp #(32) i_dividend_comp (.din(q_ff[31:0]), .dout(dividend_comp[31:0])); rvtwoscomp #(32) i_q_ff_comp (.din(q_ff[31:0]), .dout(q_ff_comp[31:0])); rvtwoscomp #(32) i_a_ff_comp (.din(a_ff[31:0]), .dout(a_ff_comp[31:0])); assign valid_x = valid_ff_x & ~cancel; // START - short circuit logic for small numbers {{ // small number divides - any 4b / 4b is done in 1 cycle (divisor != 0) // to generate espresso equations: // 1. smalldiv > smalldiv.e // 2. espresso -Dso -oeqntott smalldiv.e | addassign > smalldiv // smallnum case does not cover divide by 0 assign smallnum_case = ((q_ff[31:4] == 28'b0) & (m_ff[31:4] == 28'b0) & (m_ff[31:0] != 32'b0) & ~rem_ff & valid_x) | ((q_ff[31:0] == 32'b0) & (m_ff[31:0] != 32'b0) & ~rem_ff & valid_x); assign smallnum[3] = ( q_ff[3] & ~m_ff[3] & ~m_ff[2] & ~m_ff[1] ); assign smallnum[2] = ( q_ff[3] & ~m_ff[3] & ~m_ff[2] & ~m_ff[0]) | ( q_ff[2] & ~m_ff[3] & ~m_ff[2] & ~m_ff[1] ) | ( q_ff[3] & q_ff[2] & ~m_ff[3] & ~m_ff[2] ); assign smallnum[1] = ( q_ff[2] & ~m_ff[3] & ~m_ff[2] & ~m_ff[0]) | ( q_ff[1] & ~m_ff[3] & ~m_ff[2] & ~m_ff[1] ) | ( q_ff[3] & ~m_ff[3] & ~m_ff[1] & ~m_ff[0]) | ( q_ff[3] & ~q_ff[2] & ~m_ff[3] & ~m_ff[2] & m_ff[1] & m_ff[0]) | (~q_ff[3] & q_ff[2] & q_ff[1] & ~m_ff[3] & ~m_ff[2] ) | ( q_ff[3] & q_ff[2] & ~m_ff[3] & ~m_ff[0]) | ( q_ff[3] & q_ff[2] & ~m_ff[3] & m_ff[2] & ~m_ff[1] ) | ( q_ff[3] & q_ff[1] & ~m_ff[3] & ~m_ff[1] ) | ( q_ff[3] & q_ff[2] & q_ff[1] & ~m_ff[3] & m_ff[2] ); assign smallnum[0] = ( q_ff[2] & q_ff[1] & q_ff[0] & ~m_ff[3] & ~m_ff[1] ) | ( q_ff[3] & ~q_ff[2] & q_ff[0] & ~m_ff[3] & m_ff[1] & m_ff[0]) | ( q_ff[2] & ~m_ff[3] & ~m_ff[1] & ~m_ff[0]) | ( q_ff[1] & ~m_ff[3] & ~m_ff[2] & ~m_ff[0]) | ( q_ff[0] & ~m_ff[3] & ~m_ff[2] & ~m_ff[1] ) | (~q_ff[3] & q_ff[2] & ~q_ff[1] & ~m_ff[3] & ~m_ff[2] & m_ff[1] & m_ff[0]) | (~q_ff[3] & q_ff[2] & q_ff[1] & ~m_ff[3] & ~m_ff[0]) | ( q_ff[3] & ~m_ff[2] & ~m_ff[1] & ~m_ff[0]) | ( q_ff[3] & ~q_ff[2] & ~m_ff[3] & m_ff[2] & m_ff[1] ) | (~q_ff[3] & q_ff[2] & q_ff[1] & ~m_ff[3] & m_ff[2] & ~m_ff[1] ) | (~q_ff[3] & q_ff[2] & q_ff[0] & ~m_ff[3] & ~m_ff[1] ) | ( q_ff[3] & ~q_ff[2] & ~q_ff[1] & ~m_ff[3] & m_ff[2] & m_ff[0]) | ( ~q_ff[2] & q_ff[1] & q_ff[0] & ~m_ff[3] & ~m_ff[2] ) | ( q_ff[3] & q_ff[2] & ~m_ff[1] & ~m_ff[0]) | ( q_ff[3] & q_ff[1] & ~m_ff[2] & ~m_ff[0]) | (~q_ff[3] & q_ff[2] & q_ff[1] & q_ff[0] & ~m_ff[3] & m_ff[2] ) | ( q_ff[3] & q_ff[2] & m_ff[3] & ~m_ff[2] ) | ( q_ff[3] & q_ff[1] & m_ff[3] & ~m_ff[2] & ~m_ff[1] ) | ( q_ff[3] & q_ff[0] & ~m_ff[2] & ~m_ff[1] ) | ( q_ff[3] & ~q_ff[1] & ~m_ff[3] & m_ff[2] & m_ff[1] & m_ff[0]) | ( q_ff[3] & q_ff[2] & q_ff[1] & m_ff[3] & ~m_ff[0]) | ( q_ff[3] & q_ff[2] & q_ff[1] & m_ff[3] & ~m_ff[1] ) | ( q_ff[3] & q_ff[2] & q_ff[0] & m_ff[3] & ~m_ff[1] ) | ( q_ff[3] & ~q_ff[2] & q_ff[1] & ~m_ff[3] & m_ff[1] ) | ( q_ff[3] & q_ff[1] & q_ff[0] & ~m_ff[2] ) | ( q_ff[3] & q_ff[2] & q_ff[1] & q_ff[0] & m_ff[3] ); // END - short circuit logic for small numbers }} // *** Start Short Q *** {{ assign short_dividend[31:0] = q_ff[31:0]; assign short_dividend[32] = sign_ff & q_ff[31]; // A B // 210 210 SH // --- --- -- // 1xx 000 0 // 1xx 001 8 // 1xx 01x 16 // 1xx 1xx 24 // 01x 000 8 // 01x 001 16 // 01x 01x 24 // 01x 1xx 32 // 001 000 16 // 001 001 24 // 001 01x 32 // 001 1xx 32 // 000 000 24 // 000 001 32 // 000 01x 32 // 000 1xx 32 assign a_cls[4:3] = 2'b0; assign a_cls[2] = (~short_dividend[32] & (short_dividend[31:24] != {8{1'b0}})) | ( short_dividend[32] & (short_dividend[31:23] != {9{1'b1}})); assign a_cls[1] = (~short_dividend[32] & (short_dividend[23:16] != {8{1'b0}})) | ( short_dividend[32] & (short_dividend[22:15] != {8{1'b1}})); assign a_cls[0] = (~short_dividend[32] & (short_dividend[15:08] != {8{1'b0}})) | ( short_dividend[32] & (short_dividend[14:07] != {8{1'b1}})); assign b_cls[4:3] = 2'b0; assign b_cls[2] = (~m_ff[32] & ( m_ff[31:24] != {8{1'b0}})) | ( m_ff[32] & ( m_ff[31:24] != {8{1'b1}})); assign b_cls[1] = (~m_ff[32] & ( m_ff[23:16] != {8{1'b0}})) | ( m_ff[32] & ( m_ff[23:16] != {8{1'b1}})); assign b_cls[0] = (~m_ff[32] & ( m_ff[15:08] != {8{1'b0}})) | ( m_ff[32] & ( m_ff[15:08] != {8{1'b1}})); assign shortq_raw[3] = ( (a_cls[2:1] == 2'b01 ) & (b_cls[2] == 1'b1 ) ) | // Shift by 32 ( (a_cls[2:0] == 3'b001) & (b_cls[2] == 1'b1 ) ) | ( (a_cls[2:0] == 3'b000) & (b_cls[2] == 1'b1 ) ) | ( (a_cls[2:0] == 3'b001) & (b_cls[2:1] == 2'b01 ) ) | ( (a_cls[2:0] == 3'b000) & (b_cls[2:1] == 2'b01 ) ) | ( (a_cls[2:0] == 3'b000) & (b_cls[2:0] == 3'b001) ); assign shortq_raw[2] = ( (a_cls[2] == 1'b1 ) & (b_cls[2] == 1'b1 ) ) | // Shift by 24 ( (a_cls[2:1] == 2'b01 ) & (b_cls[2:1] == 2'b01 ) ) | ( (a_cls[2:0] == 3'b001) & (b_cls[2:0] == 3'b001) ) | ( (a_cls[2:0] == 3'b000) & (b_cls[2:0] == 3'b000) ); assign shortq_raw[1] = ( (a_cls[2] == 1'b1 ) & (b_cls[2:1] == 2'b01 ) ) | // Shift by 16 ( (a_cls[2:1] == 2'b01 ) & (b_cls[2:0] == 3'b001) ) | ( (a_cls[2:0] == 3'b001) & (b_cls[2:0] == 3'b000) ); assign shortq_raw[0] = ( (a_cls[2] == 1'b1 ) & (b_cls[2:0] == 3'b001) ) | // Shift by 8 ( (a_cls[2:1] == 2'b01 ) & (b_cls[2:0] == 3'b000) ); assign shortq_enable = valid_ff_x & (m_ff[31:0] != 32'b0) & (shortq_raw[3:0] != 4'b0); assign shortq_shift[3:0] = ({4{shortq_enable}} & shortq_raw[3:0]); assign shortq[5:0] = 6'b0; assign shortq_shift[5:4] = 2'b0; assign shortq_shift_ff[5] = 1'b0; assign shortq_shift_ff[4:0] = ({5{shortq_shift_xx[3]}} & 5'b1_1111) | // 31 ({5{shortq_shift_xx[2]}} & 5'b1_1000) | // 24 ({5{shortq_shift_xx[1]}} & 5'b1_0000) | // 16 ({5{shortq_shift_xx[0]}} & 5'b0_1000); // 8 // *** End Short *** }} assign div_clken = valid_in | run_state | finish | finish_ff; assign run_in = (valid_in | run_state) & ~finish & ~cancel; assign count_in[5:0] = {6{run_state & ~finish & ~cancel & ~shortq_enable}} & (count[5:0] + {1'b0,shortq_shift_ff[4:0]} + 6'd1); assign finish = (smallnum_case | ((~rem_ff) ? (count[5:0] == 6'd32) : (count[5:0] == 6'd33))); assign valid_out = finish_ff & ~cancel; assign sign_eff = signed_in & (divisor_in[31:0] != 32'b0); assign q_in[32:0] = ({33{~run_state }} & {1'b0,dividend_in[31:0]}) | ({33{ run_state & (valid_ff_x | shortq_enable_ff)}} & ({dividend_eff[31:0], ~a_in[32]} << shortq_shift_ff[4:0])) | ({33{ run_state & ~(valid_ff_x | shortq_enable_ff)}} & {q_ff[31:0], ~a_in[32]}); assign qff_enable = valid_in | (run_state & ~shortq_enable); assign dividend_eff[31:0] = (sign_ff & dividend_neg_ff) ? dividend_comp[31:0] : q_ff[31:0]; assign m_eff[32:0] = ( add ) ? m_ff[32:0] : ~m_ff[32:0]; assign a_eff_shift[64:0] = {33'b0, dividend_eff[31:0]} << shortq_shift_ff[4:0]; assign a_eff[32:0] = ({33{ rem_correct }} & a_ff[32:0] ) | ({33{~rem_correct & ~shortq_enable_ff}} & {a_ff[31:0], q_ff[32]} ) | ({33{~rem_correct & shortq_enable_ff}} & a_eff_shift[64:32] ); assign a_shift[32:0] = {33{run_state}} & a_eff[32:0]; assign a_in[32:0] = {33{run_state}} & (a_shift[32:0] + m_eff[32:0] + {32'b0,~add}); assign aff_enable = valid_in | (run_state & ~shortq_enable & (count[5:0]!=6'd33)) | rem_correct; assign m_already_comp = (divisor_neg_ff & sign_ff); // if m already complemented, then invert operation add->sub, sub->add assign add = (a_ff[32] | rem_correct) ^ m_already_comp; assign rem_correct = (count[5:0] == 6'd33) & rem_ff & a_ff[32]; assign q_ff_eff[31:0] = (sign_ff & (dividend_neg_ff ^ divisor_neg_ff)) ? q_ff_comp[31:0] : q_ff[31:0]; assign a_ff_eff[31:0] = (sign_ff & dividend_neg_ff) ? a_ff_comp[31:0] : a_ff[31:0]; assign data_out[31:0] = ({32{ smallnum_case_ff }} & {28'b0, smallnum_ff[3:0]}) | ({32{ rem_ff}} & a_ff_eff[31:0] ) | ({32{~smallnum_case_ff & ~rem_ff}} & q_ff_eff[31:0] ); endmodule // el2_exu_div_existing_1bit_cheapshortq // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * module el2_exu_div_new_1bit_fullshortq ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan mode /*pragma coverage on*/ input logic cancel, // Flush pipeline input logic valid_in, input logic signed_in, input logic rem_in, input logic [31:0] dividend_in, input logic [31:0] divisor_in, output logic valid_out, output logic [31:0] data_out ); logic valid_ff_in, valid_ff; logic finish_raw, finish, finish_ff; logic running_state; logic misc_enable; logic [2:0] control_in, control_ff; logic dividend_sign_ff, divisor_sign_ff, rem_ff; logic count_enable; logic [6:0] count_in, count_ff; logic smallnum_case; logic [3:0] smallnum; logic a_enable, a_shift; logic [31:0] a_in, a_ff; logic b_enable, b_twos_comp; logic [32:0] b_in, b_ff; logic [31:0] q_in, q_ff; logic rq_enable, r_sign_sel, r_restore_sel, r_adder_sel; logic [31:0] r_in, r_ff; logic twos_comp_q_sel, twos_comp_b_sel; logic [31:0] twos_comp_in, twos_comp_out; logic quotient_set; logic [32:0] adder_out; logic [63:0] ar_shifted; logic [5:0] shortq; logic [4:0] shortq_shift; logic [4:0] shortq_shift_ff; logic shortq_enable; logic shortq_enable_ff; logic [32:0] shortq_dividend; logic by_zero_case; logic by_zero_case_ff; rvdffe #(19) i_misc_ff (.*, .clk(clk), .en(misc_enable), .din ({valid_ff_in, control_in[2:0], by_zero_case, shortq_enable, shortq_shift[4:0], finish, count_in[6:0]}), .dout({valid_ff, control_ff[2:0], by_zero_case_ff, shortq_enable_ff, shortq_shift_ff[4:0], finish_ff, count_ff[6:0]})); rvdffe #(32) i_a_ff (.*, .clk(clk), .en(a_enable), .din(a_in[31:0]), .dout(a_ff[31:0])); rvdffe #(33) i_b_ff (.*, .clk(clk), .en(b_enable), .din(b_in[32:0]), .dout(b_ff[32:0])); rvdffe #(32) i_r_ff (.*, .clk(clk), .en(rq_enable), .din(r_in[31:0]), .dout(r_ff[31:0])); rvdffe #(32) i_q_ff (.*, .clk(clk), .en(rq_enable), .din(q_in[31:0]), .dout(q_ff[31:0])); assign valid_ff_in = valid_in & ~cancel; assign control_in[2] = (~valid_in & control_ff[2]) | (valid_in & signed_in & dividend_in[31]); assign control_in[1] = (~valid_in & control_ff[1]) | (valid_in & signed_in & divisor_in[31]); assign control_in[0] = (~valid_in & control_ff[0]) | (valid_in & rem_in); assign dividend_sign_ff = control_ff[2]; assign divisor_sign_ff = control_ff[1]; assign rem_ff = control_ff[0]; assign by_zero_case = valid_ff & (b_ff[31:0] == 32'b0); assign misc_enable = valid_in | valid_ff | cancel | running_state | finish_ff; assign running_state = (| count_ff[6:0]) | shortq_enable_ff; assign finish_raw = smallnum_case | by_zero_case | (count_ff[6:0] == 7'd32); assign finish = finish_raw & ~cancel; assign count_enable = (valid_ff | running_state) & ~finish & ~finish_ff & ~cancel & ~shortq_enable; assign count_in[6:0] = {7{count_enable}} & (count_ff[6:0] + {6'b0,1'b1} + {2'b0,shortq_shift_ff[4:0]}); assign a_enable = valid_in | running_state; assign a_shift = running_state & ~shortq_enable_ff; assign ar_shifted[63:0] = { {32{dividend_sign_ff}} , a_ff[31:0]} << shortq_shift_ff[4:0]; assign a_in[31:0] = ( {32{~a_shift & ~shortq_enable_ff}} & dividend_in[31:0] ) | ( {32{ a_shift }} & {a_ff[30:0],1'b0} ) | ( {32{ shortq_enable_ff}} & ar_shifted[31:0] ); assign b_enable = valid_in | b_twos_comp; assign b_twos_comp = valid_ff & ~(dividend_sign_ff ^ divisor_sign_ff); assign b_in[32:0] = ( {33{~b_twos_comp}} & { (signed_in & divisor_in[31]),divisor_in[31:0] } ) | ( {33{ b_twos_comp}} & {~divisor_sign_ff,twos_comp_out[31:0] } ); assign rq_enable = valid_in | valid_ff | running_state; assign r_sign_sel = valid_ff & dividend_sign_ff & ~by_zero_case; assign r_restore_sel = running_state & ~quotient_set & ~shortq_enable_ff; assign r_adder_sel = running_state & quotient_set & ~shortq_enable_ff; assign r_in[31:0] = ( {32{r_sign_sel }} & 32'hffffffff ) | ( {32{r_restore_sel }} & {r_ff[30:0] ,a_ff[31]} ) | ( {32{r_adder_sel }} & adder_out[31:0] ) | ( {32{shortq_enable_ff}} & ar_shifted[63:32] ) | ( {32{by_zero_case }} & a_ff[31:0] ); assign q_in[31:0] = ( {32{~valid_ff }} & {q_ff[30:0], quotient_set} ) | ( {32{ smallnum_case }} & {28'b0 , smallnum[3:0]} ) | ( {32{ by_zero_case }} & {32{1'b1}} ); assign adder_out[32:0] = {r_ff[31:0],a_ff[31]} + {b_ff[32:0] }; assign quotient_set = (~adder_out[32] ^ dividend_sign_ff) | ( (a_ff[30:0] == 31'b0) & (adder_out[32:0] == 33'b0) ); assign twos_comp_b_sel = valid_ff & ~(dividend_sign_ff ^ divisor_sign_ff); assign twos_comp_q_sel = ~valid_ff & ~rem_ff & (dividend_sign_ff ^ divisor_sign_ff) & ~by_zero_case_ff; assign twos_comp_in[31:0] = ( {32{twos_comp_q_sel}} & q_ff[31:0] ) | ( {32{twos_comp_b_sel}} & b_ff[31:0] ); rvtwoscomp #(32) i_twos_comp (.din(twos_comp_in[31:0]), .dout(twos_comp_out[31:0])); assign valid_out = finish_ff & ~cancel; assign data_out[31:0] = ( {32{~rem_ff & ~twos_comp_q_sel}} & q_ff[31:0] ) | ( {32{ rem_ff }} & r_ff[31:0] ) | ( {32{ twos_comp_q_sel}} & twos_comp_out[31:0] ); // *** *** *** START : SMALLNUM {{ assign smallnum_case = ( (a_ff[31:4] == 28'b0) & (b_ff[31:4] == 28'b0) & ~by_zero_case & ~rem_ff & valid_ff & ~cancel) | ( (a_ff[31:0] == 32'b0) & ~by_zero_case & ~rem_ff & valid_ff & ~cancel); assign smallnum[3] = ( a_ff[3] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ); assign smallnum[2] = ( a_ff[3] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[2] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & ~b_ff[2] ); assign smallnum[1] = ( a_ff[2] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[1] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & ~b_ff[3] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & ~a_ff[2] & ~b_ff[3] & ~b_ff[2] & b_ff[1] & b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & ~b_ff[0]) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[1] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[2] ); assign smallnum[0] = ( a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & a_ff[0] & ~b_ff[3] & b_ff[1] & b_ff[0]) | ( a_ff[2] & ~b_ff[3] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[1] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[0] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | (~a_ff[3] & a_ff[2] & ~a_ff[1] & ~b_ff[3] & ~b_ff[2] & b_ff[1] & b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & ~b_ff[0]) | ( a_ff[3] & ~b_ff[2] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & ~a_ff[2] & ~b_ff[3] & b_ff[2] & b_ff[1] ) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[2] & ~b_ff[1] ) | (~a_ff[3] & a_ff[2] & a_ff[0] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & ~a_ff[1] & ~b_ff[3] & b_ff[2] & b_ff[0]) | ( ~a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & a_ff[1] & ~b_ff[2] & ~b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & b_ff[2] ) | ( a_ff[3] & a_ff[2] & b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[1] & b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[0] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[1] & ~b_ff[3] & b_ff[2] & b_ff[1] & b_ff[0]) | ( a_ff[3] & a_ff[2] & a_ff[1] & b_ff[3] & ~b_ff[0]) | ( a_ff[3] & a_ff[2] & a_ff[1] & b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & a_ff[0] & b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[1] ) | ( a_ff[3] & a_ff[1] & a_ff[0] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & a_ff[1] & a_ff[0] & b_ff[3] ); // *** *** *** END : SMALLNUM }} // *** *** *** Start : Short Q {{ assign shortq_dividend[32:0] = {dividend_sign_ff,a_ff[31:0]}; logic [5:0] dw_a_enc; logic [5:0] dw_b_enc; logic [6:0] dw_shortq_raw; el2_exu_div_cls i_a_cls ( .operand ( shortq_dividend[32:0] ), .cls ( dw_a_enc[4:0] )); el2_exu_div_cls i_b_cls ( .operand ( b_ff[32:0] ), .cls ( dw_b_enc[4:0] )); assign dw_a_enc[5] = 1'b0; assign dw_b_enc[5] = 1'b0; assign dw_shortq_raw[6:0] = {1'b0,dw_b_enc[5:0]} - {1'b0,dw_a_enc[5:0]} + 7'd1; assign shortq[5:0] = dw_shortq_raw[6] ? 6'd0 : dw_shortq_raw[5:0]; assign shortq_enable = valid_ff & ~shortq[5] & ~(shortq[4:1] == 4'b1111) & ~cancel; assign shortq_shift[4:0] = ~shortq_enable ? 5'd0 : (5'b11111 - shortq[4:0]); // *** *** *** End : Short Q }} endmodule // el2_exu_div_new_1bit_fullshortq // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * module el2_exu_div_new_2bit_fullshortq ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan mode /*pragma coverage on*/ input logic cancel, // Flush pipeline input logic valid_in, input logic signed_in, input logic rem_in, input logic [31:0] dividend_in, input logic [31:0] divisor_in, output logic valid_out, output logic [31:0] data_out ); logic valid_ff_in, valid_ff; logic finish_raw, finish, finish_ff; logic running_state; logic misc_enable; logic [2:0] control_in, control_ff; logic dividend_sign_ff, divisor_sign_ff, rem_ff; logic count_enable; logic [6:0] count_in, count_ff; logic smallnum_case; logic [3:0] smallnum; logic a_enable, a_shift; logic [31:0] a_in, a_ff; logic b_enable, b_twos_comp; logic [32:0] b_in; logic [34:0] b_ff; logic [31:0] q_in, q_ff; logic rq_enable, r_sign_sel, r_restore_sel, r_adder1_sel, r_adder2_sel, r_adder3_sel; logic [31:0] r_in, r_ff; logic twos_comp_q_sel, twos_comp_b_sel; logic [31:0] twos_comp_in, twos_comp_out; logic [3:1] quotient_raw; logic [1:0] quotient_new; logic [32:0] adder1_out; logic [33:0] adder2_out; logic [34:0] adder3_out; logic [63:0] ar_shifted; logic [5:0] shortq; logic [4:0] shortq_shift; logic [4:1] shortq_shift_ff; logic shortq_enable; logic shortq_enable_ff; logic [32:0] shortq_dividend; logic by_zero_case; logic by_zero_case_ff; rvdffe #(18) i_misc_ff (.*, .clk(clk), .en(misc_enable), .din ({valid_ff_in, control_in[2:0], by_zero_case, shortq_enable, shortq_shift[4:1], finish, count_in[6:0]}), .dout({valid_ff, control_ff[2:0], by_zero_case_ff, shortq_enable_ff, shortq_shift_ff[4:1], finish_ff, count_ff[6:0]})); rvdffe #(32) i_a_ff (.*, .clk(clk), .en(a_enable), .din(a_in[31:0]), .dout(a_ff[31:0])); rvdffe #(33) i_b_ff (.*, .clk(clk), .en(b_enable), .din(b_in[32:0]), .dout(b_ff[32:0])); rvdffe #(32) i_r_ff (.*, .clk(clk), .en(rq_enable), .din(r_in[31:0]), .dout(r_ff[31:0])); rvdffe #(32) i_q_ff (.*, .clk(clk), .en(rq_enable), .din(q_in[31:0]), .dout(q_ff[31:0])); assign valid_ff_in = valid_in & ~cancel; assign control_in[2] = (~valid_in & control_ff[2]) | (valid_in & signed_in & dividend_in[31]); assign control_in[1] = (~valid_in & control_ff[1]) | (valid_in & signed_in & divisor_in[31]); assign control_in[0] = (~valid_in & control_ff[0]) | (valid_in & rem_in); assign dividend_sign_ff = control_ff[2]; assign divisor_sign_ff = control_ff[1]; assign rem_ff = control_ff[0]; assign by_zero_case = valid_ff & (b_ff[31:0] == 32'b0); assign misc_enable = valid_in | valid_ff | cancel | running_state | finish_ff; assign running_state = (| count_ff[6:0]) | shortq_enable_ff; assign finish_raw = smallnum_case | by_zero_case | (count_ff[6:0] == 7'd32); assign finish = finish_raw & ~cancel; assign count_enable = (valid_ff | running_state) & ~finish & ~finish_ff & ~cancel & ~shortq_enable; assign count_in[6:0] = {7{count_enable}} & (count_ff[6:0] + {5'b0,2'b10} + {2'b0,shortq_shift_ff[4:1],1'b0}); assign a_enable = valid_in | running_state; assign a_shift = running_state & ~shortq_enable_ff; assign ar_shifted[63:0] = { {32{dividend_sign_ff}} , a_ff[31:0]} << {shortq_shift_ff[4:1],1'b0}; assign a_in[31:0] = ( {32{~a_shift & ~shortq_enable_ff}} & dividend_in[31:0] ) | ( {32{ a_shift }} & {a_ff[29:0],2'b0} ) | ( {32{ shortq_enable_ff}} & ar_shifted[31:0] ); assign b_enable = valid_in | b_twos_comp; assign b_twos_comp = valid_ff & ~(dividend_sign_ff ^ divisor_sign_ff); assign b_in[32:0] = ( {33{~b_twos_comp}} & { (signed_in & divisor_in[31]),divisor_in[31:0] } ) | ( {33{ b_twos_comp}} & {~divisor_sign_ff,twos_comp_out[31:0] } ); assign rq_enable = valid_in | valid_ff | running_state; assign r_sign_sel = valid_ff & dividend_sign_ff & ~by_zero_case; assign r_restore_sel = running_state & (quotient_new[1:0] == 2'b00) & ~shortq_enable_ff; assign r_adder1_sel = running_state & (quotient_new[1:0] == 2'b01) & ~shortq_enable_ff; assign r_adder2_sel = running_state & (quotient_new[1:0] == 2'b10) & ~shortq_enable_ff; assign r_adder3_sel = running_state & (quotient_new[1:0] == 2'b11) & ~shortq_enable_ff; assign r_in[31:0] = ( {32{r_sign_sel }} & 32'hffffffff ) | ( {32{r_restore_sel }} & {r_ff[29:0] ,a_ff[31:30]} ) | ( {32{r_adder1_sel }} & adder1_out[31:0] ) | ( {32{r_adder2_sel }} & adder2_out[31:0] ) | ( {32{r_adder3_sel }} & adder3_out[31:0] ) | ( {32{shortq_enable_ff}} & ar_shifted[63:32] ) | ( {32{by_zero_case }} & a_ff[31:0] ); assign q_in[31:0] = ( {32{~valid_ff }} & {q_ff[29:0], quotient_new[1:0]} ) | ( {32{ smallnum_case }} & {28'b0 , smallnum[3:0]} ) | ( {32{ by_zero_case }} & {32{1'b1}} ); assign b_ff[34:33] = {b_ff[32],b_ff[32]}; assign adder1_out[32:0] = { r_ff[30:0],a_ff[31:30]} + b_ff[32:0]; assign adder2_out[33:0] = { r_ff[31:0],a_ff[31:30]} + {b_ff[32:0],1'b0}; assign adder3_out[34:0] = {r_ff[31],r_ff[31:0],a_ff[31:30]} + {b_ff[33:0],1'b0} + b_ff[34:0]; assign quotient_raw[1] = (~adder1_out[32] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder1_out[32:0] == 33'b0) ); assign quotient_raw[2] = (~adder2_out[33] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder2_out[33:0] == 34'b0) ); assign quotient_raw[3] = (~adder3_out[34] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder3_out[34:0] == 35'b0) ); assign quotient_new[1] = quotient_raw[3] | quotient_raw[2]; assign quotient_new[0] = quotient_raw[3] |(~quotient_raw[2] & quotient_raw[1]); assign twos_comp_b_sel = valid_ff & ~(dividend_sign_ff ^ divisor_sign_ff); assign twos_comp_q_sel = ~valid_ff & ~rem_ff & (dividend_sign_ff ^ divisor_sign_ff) & ~by_zero_case_ff; assign twos_comp_in[31:0] = ( {32{twos_comp_q_sel}} & q_ff[31:0] ) | ( {32{twos_comp_b_sel}} & b_ff[31:0] ); rvtwoscomp #(32) i_twos_comp (.din(twos_comp_in[31:0]), .dout(twos_comp_out[31:0])); assign valid_out = finish_ff & ~cancel; assign data_out[31:0] = ( {32{~rem_ff & ~twos_comp_q_sel}} & q_ff[31:0] ) | ( {32{ rem_ff }} & r_ff[31:0] ) | ( {32{ twos_comp_q_sel}} & twos_comp_out[31:0] ); // *** *** *** START : SMALLNUM {{ assign smallnum_case = ( (a_ff[31:4] == 28'b0) & (b_ff[31:4] == 28'b0) & ~by_zero_case & ~rem_ff & valid_ff & ~cancel) | ( (a_ff[31:0] == 32'b0) & ~by_zero_case & ~rem_ff & valid_ff & ~cancel); assign smallnum[3] = ( a_ff[3] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ); assign smallnum[2] = ( a_ff[3] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[2] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & ~b_ff[2] ); assign smallnum[1] = ( a_ff[2] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[1] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & ~b_ff[3] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & ~a_ff[2] & ~b_ff[3] & ~b_ff[2] & b_ff[1] & b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & ~b_ff[0]) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[1] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[2] ); assign smallnum[0] = ( a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & a_ff[0] & ~b_ff[3] & b_ff[1] & b_ff[0]) | ( a_ff[2] & ~b_ff[3] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[1] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[0] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | (~a_ff[3] & a_ff[2] & ~a_ff[1] & ~b_ff[3] & ~b_ff[2] & b_ff[1] & b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & ~b_ff[0]) | ( a_ff[3] & ~b_ff[2] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & ~a_ff[2] & ~b_ff[3] & b_ff[2] & b_ff[1] ) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[2] & ~b_ff[1] ) | (~a_ff[3] & a_ff[2] & a_ff[0] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & ~a_ff[1] & ~b_ff[3] & b_ff[2] & b_ff[0]) | ( ~a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & a_ff[1] & ~b_ff[2] & ~b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & b_ff[2] ) | ( a_ff[3] & a_ff[2] & b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[1] & b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[0] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[1] & ~b_ff[3] & b_ff[2] & b_ff[1] & b_ff[0]) | ( a_ff[3] & a_ff[2] & a_ff[1] & b_ff[3] & ~b_ff[0]) | ( a_ff[3] & a_ff[2] & a_ff[1] & b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & a_ff[0] & b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[1] ) | ( a_ff[3] & a_ff[1] & a_ff[0] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & a_ff[1] & a_ff[0] & b_ff[3] ); // *** *** *** END : SMALLNUM }} // *** *** *** Start : Short Q {{ assign shortq_dividend[32:0] = {dividend_sign_ff,a_ff[31:0]}; logic [5:0] dw_a_enc; logic [5:0] dw_b_enc; logic [6:0] dw_shortq_raw; el2_exu_div_cls i_a_cls ( .operand ( shortq_dividend[32:0] ), .cls ( dw_a_enc[4:0] )); el2_exu_div_cls i_b_cls ( .operand ( b_ff[32:0] ), .cls ( dw_b_enc[4:0] )); assign dw_a_enc[5] = 1'b0; assign dw_b_enc[5] = 1'b0; assign dw_shortq_raw[6:0] = {1'b0,dw_b_enc[5:0]} - {1'b0,dw_a_enc[5:0]} + 7'd1; assign shortq[5:0] = dw_shortq_raw[6] ? 6'd0 : dw_shortq_raw[5:0]; assign shortq_enable = valid_ff & ~shortq[5] & ~(shortq[4:1] == 4'b1111) & ~cancel; assign shortq_shift[4:0] = ~shortq_enable ? 5'd0 : (5'b11111 - shortq[4:0]); // [0] is unused // *** *** *** End : Short Q }} endmodule // el2_exu_div_new_2bit_fullshortq // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * module el2_exu_div_new_3bit_fullshortq ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan mode /*pragma coverage on*/ input logic cancel, // Flush pipeline input logic valid_in, input logic signed_in, input logic rem_in, input logic [31:0] dividend_in, input logic [31:0] divisor_in, output logic valid_out, output logic [31:0] data_out ); logic valid_ff_in, valid_ff; logic finish_raw, finish, finish_ff; logic running_state; logic misc_enable; logic [2:0] control_in, control_ff; logic dividend_sign_ff, divisor_sign_ff, rem_ff; logic count_enable; logic [6:0] count_in, count_ff; logic smallnum_case; logic [3:0] smallnum; logic a_enable, a_shift; logic [32:0] a_in, a_ff; logic b_enable, b_twos_comp; logic [32:0] b_in; logic [36:0] b_ff; logic [31:0] q_in, q_ff; logic rq_enable; logic r_sign_sel; logic r_restore_sel; logic r_adder1_sel, r_adder2_sel, r_adder3_sel, r_adder4_sel, r_adder5_sel, r_adder6_sel, r_adder7_sel; logic [32:0] r_in, r_ff; logic twos_comp_q_sel, twos_comp_b_sel; logic [31:0] twos_comp_in, twos_comp_out; logic [7:1] quotient_raw; logic [2:0] quotient_new; logic [33:0] adder1_out; logic [34:0] adder2_out; logic [35:0] adder3_out; logic [36:0] adder4_out; logic [36:0] adder5_out; logic [36:0] adder6_out; logic [36:0] adder7_out; logic [65:0] ar_shifted; logic [5:0] shortq; logic [4:0] shortq_shift; logic [4:0] shortq_decode; logic [4:0] shortq_shift_ff; logic shortq_enable; logic shortq_enable_ff; logic [32:0] shortq_dividend; logic by_zero_case; logic by_zero_case_ff; rvdffe #(19) i_misc_ff (.*, .clk(clk), .en(misc_enable), .din ({valid_ff_in, control_in[2:0], by_zero_case, shortq_enable, shortq_shift[4:0], finish, count_in[6:0]}), .dout({valid_ff, control_ff[2:0], by_zero_case_ff, shortq_enable_ff, shortq_shift_ff[4:0], finish_ff, count_ff[6:0]})); rvdffe #(33) i_a_ff (.*, .clk(clk), .en(a_enable), .din(a_in[32:0]), .dout(a_ff[32:0])); rvdffe #(33) i_b_ff (.*, .clk(clk), .en(b_enable), .din(b_in[32:0]), .dout(b_ff[32:0])); rvdffe #(33) i_r_ff (.*, .clk(clk), .en(rq_enable), .din(r_in[32:0]), .dout(r_ff[32:0])); rvdffe #(32) i_q_ff (.*, .clk(clk), .en(rq_enable), .din(q_in[31:0]), .dout(q_ff[31:0])); assign valid_ff_in = valid_in & ~cancel; assign control_in[2] = (~valid_in & control_ff[2]) | (valid_in & signed_in & dividend_in[31]); assign control_in[1] = (~valid_in & control_ff[1]) | (valid_in & signed_in & divisor_in[31]); assign control_in[0] = (~valid_in & control_ff[0]) | (valid_in & rem_in); assign dividend_sign_ff = control_ff[2]; assign divisor_sign_ff = control_ff[1]; assign rem_ff = control_ff[0]; assign by_zero_case = valid_ff & (b_ff[31:0] == 32'b0); assign misc_enable = valid_in | valid_ff | cancel | running_state | finish_ff; assign running_state = (| count_ff[6:0]) | shortq_enable_ff; assign finish_raw = smallnum_case | by_zero_case | (count_ff[6:0] == 7'd33); assign finish = finish_raw & ~cancel; assign count_enable = (valid_ff | running_state) & ~finish & ~finish_ff & ~cancel & ~shortq_enable; assign count_in[6:0] = {7{count_enable}} & (count_ff[6:0] + {5'b0,2'b11} + {2'b0,shortq_shift_ff[4:0]}); assign a_enable = valid_in | running_state; assign a_shift = running_state & ~shortq_enable_ff; assign ar_shifted[65:0] = { {33{dividend_sign_ff}} , a_ff[32:0]} << {shortq_shift_ff[4:0]}; assign a_in[32:0] = ( {33{~a_shift & ~shortq_enable_ff}} & {signed_in & dividend_in[31],dividend_in[31:0]} ) | ( {33{ a_shift }} & {a_ff[29:0],3'b0} ) | ( {33{ shortq_enable_ff}} & ar_shifted[32:0] ); assign b_enable = valid_in | b_twos_comp; assign b_twos_comp = valid_ff & ~(dividend_sign_ff ^ divisor_sign_ff); assign b_in[32:0] = ( {33{~b_twos_comp}} & { (signed_in & divisor_in[31]),divisor_in[31:0] } ) | ( {33{ b_twos_comp}} & {~divisor_sign_ff,twos_comp_out[31:0] } ); assign rq_enable = valid_in | valid_ff | running_state; assign r_sign_sel = valid_ff & dividend_sign_ff & ~by_zero_case; assign r_restore_sel = running_state & (quotient_new[2:0] == 3'b000) & ~shortq_enable_ff; assign r_adder1_sel = running_state & (quotient_new[2:0] == 3'b001) & ~shortq_enable_ff; assign r_adder2_sel = running_state & (quotient_new[2:0] == 3'b010) & ~shortq_enable_ff; assign r_adder3_sel = running_state & (quotient_new[2:0] == 3'b011) & ~shortq_enable_ff; assign r_adder4_sel = running_state & (quotient_new[2:0] == 3'b100) & ~shortq_enable_ff; assign r_adder5_sel = running_state & (quotient_new[2:0] == 3'b101) & ~shortq_enable_ff; assign r_adder6_sel = running_state & (quotient_new[2:0] == 3'b110) & ~shortq_enable_ff; assign r_adder7_sel = running_state & (quotient_new[2:0] == 3'b111) & ~shortq_enable_ff; assign r_in[32:0] = ( {33{r_sign_sel }} & {33{1'b1}} ) | ( {33{r_restore_sel }} & {r_ff[29:0] ,a_ff[32:30]} ) | ( {33{r_adder1_sel }} & adder1_out[32:0] ) | ( {33{r_adder2_sel }} & adder2_out[32:0] ) | ( {33{r_adder3_sel }} & adder3_out[32:0] ) | ( {33{r_adder4_sel }} & adder4_out[32:0] ) | ( {33{r_adder5_sel }} & adder5_out[32:0] ) | ( {33{r_adder6_sel }} & adder6_out[32:0] ) | ( {33{r_adder7_sel }} & adder7_out[32:0] ) | ( {33{shortq_enable_ff}} & ar_shifted[65:33] ) | ( {33{by_zero_case }} & {1'b0,a_ff[31:0]} ); assign q_in[31:0] = ( {32{~valid_ff }} & {q_ff[28:0], quotient_new[2:0]} ) | ( {32{ smallnum_case}} & {28'b0 , smallnum[3:0]} ) | ( {32{ by_zero_case }} & {32{1'b1}} ); assign b_ff[36:33] = {b_ff[32],b_ff[32],b_ff[32],b_ff[32]}; assign adder1_out[33:0] = { r_ff[30:0],a_ff[32:30]} + b_ff[33:0]; assign adder2_out[34:0] = { r_ff[31:0],a_ff[32:30]} + {b_ff[33:0],1'b0}; assign adder3_out[35:0] = { r_ff[32:0],a_ff[32:30]} + {b_ff[34:0],1'b0} + b_ff[35:0]; assign adder4_out[36:0] = {r_ff[32],r_ff[32:0],a_ff[32:30]} + {b_ff[34:0],2'b0}; assign adder5_out[36:0] = {r_ff[32],r_ff[32:0],a_ff[32:30]} + {b_ff[34:0],2'b0} + b_ff[36:0]; assign adder6_out[36:0] = {r_ff[32],r_ff[32:0],a_ff[32:30]} + {b_ff[34:0],2'b0} + {b_ff[35:0],1'b0}; assign adder7_out[36:0] = {r_ff[32],r_ff[32:0],a_ff[32:30]} + {b_ff[34:0],2'b0} + {b_ff[35:0],1'b0} + b_ff[36:0]; assign quotient_raw[1] = (~adder1_out[33] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder1_out[33:0] == 34'b0) ); assign quotient_raw[2] = (~adder2_out[34] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder2_out[34:0] == 35'b0) ); assign quotient_raw[3] = (~adder3_out[35] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder3_out[35:0] == 36'b0) ); assign quotient_raw[4] = (~adder4_out[36] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder4_out[36:0] == 37'b0) ); assign quotient_raw[5] = (~adder5_out[36] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder5_out[36:0] == 37'b0) ); assign quotient_raw[6] = (~adder6_out[36] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder6_out[36:0] == 37'b0) ); assign quotient_raw[7] = (~adder7_out[36] ^ dividend_sign_ff) | ( (a_ff[29:0] == 30'b0) & (adder7_out[36:0] == 37'b0) ); assign quotient_new[2] = quotient_raw[7] | quotient_raw[6] | quotient_raw[5] | quotient_raw[4]; assign quotient_new[1] = quotient_raw[7] | quotient_raw[6] | (~quotient_raw[4] & quotient_raw[3]) | (~quotient_raw[3] & quotient_raw[2]); assign quotient_new[0] = quotient_raw[7] | (~quotient_raw[6] & quotient_raw[5]) | (~quotient_raw[4] & quotient_raw[3]) | (~quotient_raw[2] & quotient_raw[1]); assign twos_comp_b_sel = valid_ff & ~(dividend_sign_ff ^ divisor_sign_ff); assign twos_comp_q_sel = ~valid_ff & ~rem_ff & (dividend_sign_ff ^ divisor_sign_ff) & ~by_zero_case_ff; assign twos_comp_in[31:0] = ( {32{twos_comp_q_sel}} & q_ff[31:0] ) | ( {32{twos_comp_b_sel}} & b_ff[31:0] ); rvtwoscomp #(32) i_twos_comp (.din(twos_comp_in[31:0]), .dout(twos_comp_out[31:0])); assign valid_out = finish_ff & ~cancel; assign data_out[31:0] = ( {32{~rem_ff & ~twos_comp_q_sel}} & q_ff[31:0] ) | ( {32{ rem_ff }} & r_ff[31:0] ) | ( {32{ twos_comp_q_sel}} & twos_comp_out[31:0] ); // *** *** *** START : SMALLNUM {{ assign smallnum_case = ( (a_ff[31:4] == 28'b0) & (b_ff[31:4] == 28'b0) & ~by_zero_case & ~rem_ff & valid_ff & ~cancel) | ( (a_ff[31:0] == 32'b0) & ~by_zero_case & ~rem_ff & valid_ff & ~cancel); assign smallnum[3] = ( a_ff[3] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ); assign smallnum[2] = ( a_ff[3] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[2] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & ~b_ff[2] ); assign smallnum[1] = ( a_ff[2] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[1] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & ~b_ff[3] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & ~a_ff[2] & ~b_ff[3] & ~b_ff[2] & b_ff[1] & b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & ~b_ff[0]) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[1] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[2] ); assign smallnum[0] = ( a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & a_ff[0] & ~b_ff[3] & b_ff[1] & b_ff[0]) | ( a_ff[2] & ~b_ff[3] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[1] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[0] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | (~a_ff[3] & a_ff[2] & ~a_ff[1] & ~b_ff[3] & ~b_ff[2] & b_ff[1] & b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & ~b_ff[0]) | ( a_ff[3] & ~b_ff[2] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & ~a_ff[2] & ~b_ff[3] & b_ff[2] & b_ff[1] ) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[2] & ~b_ff[1] ) | (~a_ff[3] & a_ff[2] & a_ff[0] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & ~a_ff[1] & ~b_ff[3] & b_ff[2] & b_ff[0]) | ( ~a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & a_ff[1] & ~b_ff[2] & ~b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & b_ff[2] ) | ( a_ff[3] & a_ff[2] & b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[1] & b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[0] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[1] & ~b_ff[3] & b_ff[2] & b_ff[1] & b_ff[0]) | ( a_ff[3] & a_ff[2] & a_ff[1] & b_ff[3] & ~b_ff[0]) | ( a_ff[3] & a_ff[2] & a_ff[1] & b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & a_ff[0] & b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[1] ) | ( a_ff[3] & a_ff[1] & a_ff[0] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & a_ff[1] & a_ff[0] & b_ff[3] ); // *** *** *** END : SMALLNUM }} // *** *** *** Start : Short Q {{ assign shortq_dividend[32:0] = {dividend_sign_ff,a_ff[31:0]}; logic [5:0] dw_a_enc; logic [5:0] dw_b_enc; logic [6:0] dw_shortq_raw; el2_exu_div_cls i_a_cls ( .operand ( shortq_dividend[32:0] ), .cls ( dw_a_enc[4:0] )); el2_exu_div_cls i_b_cls ( .operand ( b_ff[32:0] ), .cls ( dw_b_enc[4:0] )); assign dw_a_enc[5] = 1'b0; assign dw_b_enc[5] = 1'b0; assign dw_shortq_raw[6:0] = {1'b0,dw_b_enc[5:0]} - {1'b0,dw_a_enc[5:0]} + 7'd1; assign shortq[5:0] = dw_shortq_raw[6] ? 6'd0 : dw_shortq_raw[5:0]; assign shortq_enable = valid_ff & ~shortq[5] & ~(shortq[4:2] == 3'b111) & ~cancel; assign shortq_decode[4:0] = ( {5{shortq[4:0] == 5'd31}} & 5'd00) | ( {5{shortq[4:0] == 5'd30}} & 5'd00) | ( {5{shortq[4:0] == 5'd29}} & 5'd00) | ( {5{shortq[4:0] == 5'd28}} & 5'd00) | ( {5{shortq[4:0] == 5'd27}} & 5'd03) | ( {5{shortq[4:0] == 5'd26}} & 5'd06) | ( {5{shortq[4:0] == 5'd25}} & 5'd06) | ( {5{shortq[4:0] == 5'd24}} & 5'd06) | ( {5{shortq[4:0] == 5'd23}} & 5'd09) | ( {5{shortq[4:0] == 5'd22}} & 5'd09) | ( {5{shortq[4:0] == 5'd21}} & 5'd09) | ( {5{shortq[4:0] == 5'd20}} & 5'd12) | ( {5{shortq[4:0] == 5'd19}} & 5'd12) | ( {5{shortq[4:0] == 5'd18}} & 5'd12) | ( {5{shortq[4:0] == 5'd17}} & 5'd15) | ( {5{shortq[4:0] == 5'd16}} & 5'd15) | ( {5{shortq[4:0] == 5'd15}} & 5'd15) | ( {5{shortq[4:0] == 5'd14}} & 5'd18) | ( {5{shortq[4:0] == 5'd13}} & 5'd18) | ( {5{shortq[4:0] == 5'd12}} & 5'd18) | ( {5{shortq[4:0] == 5'd11}} & 5'd21) | ( {5{shortq[4:0] == 5'd10}} & 5'd21) | ( {5{shortq[4:0] == 5'd09}} & 5'd21) | ( {5{shortq[4:0] == 5'd08}} & 5'd24) | ( {5{shortq[4:0] == 5'd07}} & 5'd24) | ( {5{shortq[4:0] == 5'd06}} & 5'd24) | ( {5{shortq[4:0] == 5'd05}} & 5'd27) | ( {5{shortq[4:0] == 5'd04}} & 5'd27) | ( {5{shortq[4:0] == 5'd03}} & 5'd27) | ( {5{shortq[4:0] == 5'd02}} & 5'd27) | ( {5{shortq[4:0] == 5'd01}} & 5'd27) | ( {5{shortq[4:0] == 5'd00}} & 5'd27); assign shortq_shift[4:0] = ~shortq_enable ? 5'd0 : shortq_decode[4:0]; // *** *** *** End : Short Q }} endmodule // el2_exu_div_new_3bit_fullshortq // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * module el2_exu_div_new_4bit_fullshortq ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan mode /*pragma coverage on*/ input logic cancel, // Flush pipeline input logic valid_in, input logic signed_in, input logic rem_in, input logic [31:0] dividend_in, input logic [31:0] divisor_in, output logic valid_out, output logic [31:0] data_out ); logic valid_ff_in, valid_ff; logic finish_raw, finish, finish_ff; logic running_state; logic misc_enable; logic [2:0] control_in, control_ff; logic dividend_sign_ff, divisor_sign_ff, rem_ff; logic count_enable; logic [6:0] count_in, count_ff; logic smallnum_case; logic [3:0] smallnum; logic a_enable, a_shift; logic [31:0] a_in, a_ff; logic b_enable, b_twos_comp; logic [32:0] b_in; logic [37:0] b_ff; logic [31:0] q_in, q_ff; logic rq_enable; logic r_sign_sel; logic r_restore_sel; logic r_adder01_sel, r_adder02_sel, r_adder03_sel; logic r_adder04_sel, r_adder05_sel, r_adder06_sel, r_adder07_sel; logic r_adder08_sel, r_adder09_sel, r_adder10_sel, r_adder11_sel; logic r_adder12_sel, r_adder13_sel, r_adder14_sel, r_adder15_sel; logic [32:0] r_in, r_ff; logic twos_comp_q_sel, twos_comp_b_sel; logic [31:0] twos_comp_in, twos_comp_out; logic [15:1] quotient_raw; logic [3:0] quotient_new; logic [34:0] adder01_out; logic [35:0] adder02_out; logic [36:0] adder03_out; logic [37:0] adder04_out; logic [37:0] adder05_out; logic [37:0] adder06_out; logic [37:0] adder07_out; logic [37:0] adder08_out; logic [37:0] adder09_out; logic [37:0] adder10_out; logic [37:0] adder11_out; logic [37:0] adder12_out; logic [37:0] adder13_out; logic [37:0] adder14_out; logic [37:0] adder15_out; logic [64:0] ar_shifted; logic [5:0] shortq; logic [4:0] shortq_shift; logic [4:0] shortq_decode; logic [4:0] shortq_shift_ff; logic shortq_enable; logic shortq_enable_ff; logic [32:0] shortq_dividend; logic by_zero_case; logic by_zero_case_ff; rvdffe #(19) i_misc_ff (.*, .clk(clk), .en(misc_enable), .din ({valid_ff_in, control_in[2:0], by_zero_case, shortq_enable, shortq_shift[4:0], finish, count_in[6:0]}), .dout({valid_ff, control_ff[2:0], by_zero_case_ff, shortq_enable_ff, shortq_shift_ff[4:0], finish_ff, count_ff[6:0]})); rvdffe #(32) i_a_ff (.*, .clk(clk), .en(a_enable), .din(a_in[31:0]), .dout(a_ff[31:0])); rvdffe #(33) i_b_ff (.*, .clk(clk), .en(b_enable), .din(b_in[32:0]), .dout(b_ff[32:0])); rvdffe #(33) i_r_ff (.*, .clk(clk), .en(rq_enable), .din(r_in[32:0]), .dout(r_ff[32:0])); rvdffe #(32) i_q_ff (.*, .clk(clk), .en(rq_enable), .din(q_in[31:0]), .dout(q_ff[31:0])); assign valid_ff_in = valid_in & ~cancel; assign control_in[2] = (~valid_in & control_ff[2]) | (valid_in & signed_in & dividend_in[31]); assign control_in[1] = (~valid_in & control_ff[1]) | (valid_in & signed_in & divisor_in[31]); assign control_in[0] = (~valid_in & control_ff[0]) | (valid_in & rem_in); assign dividend_sign_ff = control_ff[2]; assign divisor_sign_ff = control_ff[1]; assign rem_ff = control_ff[0]; assign by_zero_case = valid_ff & (b_ff[31:0] == 32'b0); assign misc_enable = valid_in | valid_ff | cancel | running_state | finish_ff; assign running_state = (| count_ff[6:0]) | shortq_enable_ff; assign finish_raw = smallnum_case | by_zero_case | (count_ff[6:0] == 7'd32); assign finish = finish_raw & ~cancel; assign count_enable = (valid_ff | running_state) & ~finish & ~finish_ff & ~cancel & ~shortq_enable; assign count_in[6:0] = {7{count_enable}} & (count_ff[6:0] + 7'd4 + {2'b0,shortq_shift_ff[4:0]}); assign a_enable = valid_in | running_state; assign a_shift = running_state & ~shortq_enable_ff; assign ar_shifted[64:0] = { {33{dividend_sign_ff}} , a_ff[31:0]} << {shortq_shift_ff[4:0]}; assign a_in[31:0] = ( {32{~a_shift & ~shortq_enable_ff}} & dividend_in[31:0] ) | ( {32{ a_shift }} & {a_ff[27:0],4'b0} ) | ( {32{ shortq_enable_ff}} & ar_shifted[31:0] ); assign b_enable = valid_in | b_twos_comp; assign b_twos_comp = valid_ff & ~(dividend_sign_ff ^ divisor_sign_ff); assign b_in[32:0] = ( {33{~b_twos_comp}} & { (signed_in & divisor_in[31]),divisor_in[31:0] } ) | ( {33{ b_twos_comp}} & {~divisor_sign_ff,twos_comp_out[31:0] } ); assign rq_enable = valid_in | valid_ff | running_state; assign r_sign_sel = valid_ff & dividend_sign_ff & ~by_zero_case; assign r_restore_sel = running_state & (quotient_new[3:0] == 4'd00) & ~shortq_enable_ff; assign r_adder01_sel = running_state & (quotient_new[3:0] == 4'd01) & ~shortq_enable_ff; assign r_adder02_sel = running_state & (quotient_new[3:0] == 4'd02) & ~shortq_enable_ff; assign r_adder03_sel = running_state & (quotient_new[3:0] == 4'd03) & ~shortq_enable_ff; assign r_adder04_sel = running_state & (quotient_new[3:0] == 4'd04) & ~shortq_enable_ff; assign r_adder05_sel = running_state & (quotient_new[3:0] == 4'd05) & ~shortq_enable_ff; assign r_adder06_sel = running_state & (quotient_new[3:0] == 4'd06) & ~shortq_enable_ff; assign r_adder07_sel = running_state & (quotient_new[3:0] == 4'd07) & ~shortq_enable_ff; assign r_adder08_sel = running_state & (quotient_new[3:0] == 4'd08) & ~shortq_enable_ff; assign r_adder09_sel = running_state & (quotient_new[3:0] == 4'd09) & ~shortq_enable_ff; assign r_adder10_sel = running_state & (quotient_new[3:0] == 4'd10) & ~shortq_enable_ff; assign r_adder11_sel = running_state & (quotient_new[3:0] == 4'd11) & ~shortq_enable_ff; assign r_adder12_sel = running_state & (quotient_new[3:0] == 4'd12) & ~shortq_enable_ff; assign r_adder13_sel = running_state & (quotient_new[3:0] == 4'd13) & ~shortq_enable_ff; assign r_adder14_sel = running_state & (quotient_new[3:0] == 4'd14) & ~shortq_enable_ff; assign r_adder15_sel = running_state & (quotient_new[3:0] == 4'd15) & ~shortq_enable_ff; assign r_in[32:0] = ( {33{r_sign_sel }} & {33{1'b1}} ) | ( {33{r_restore_sel }} & {r_ff[28:0],a_ff[31:28]} ) | ( {33{r_adder01_sel }} & adder01_out[32:0] ) | ( {33{r_adder02_sel }} & adder02_out[32:0] ) | ( {33{r_adder03_sel }} & adder03_out[32:0] ) | ( {33{r_adder04_sel }} & adder04_out[32:0] ) | ( {33{r_adder05_sel }} & adder05_out[32:0] ) | ( {33{r_adder06_sel }} & adder06_out[32:0] ) | ( {33{r_adder07_sel }} & adder07_out[32:0] ) | ( {33{r_adder08_sel }} & adder08_out[32:0] ) | ( {33{r_adder09_sel }} & adder09_out[32:0] ) | ( {33{r_adder10_sel }} & adder10_out[32:0] ) | ( {33{r_adder11_sel }} & adder11_out[32:0] ) | ( {33{r_adder12_sel }} & adder12_out[32:0] ) | ( {33{r_adder13_sel }} & adder13_out[32:0] ) | ( {33{r_adder14_sel }} & adder14_out[32:0] ) | ( {33{r_adder15_sel }} & adder15_out[32:0] ) | ( {33{shortq_enable_ff}} & ar_shifted[64:32] ) | ( {33{by_zero_case }} & {1'b0,a_ff[31:0]} ); assign q_in[31:0] = ( {32{~valid_ff }} & {q_ff[27:0], quotient_new[3:0]} ) | ( {32{ smallnum_case}} & {28'b0 , smallnum[3:0]} ) | ( {32{ by_zero_case }} & {32{1'b1}} ); assign b_ff[37:33] = {b_ff[32],b_ff[32],b_ff[32],b_ff[32],b_ff[32]}; assign adder01_out[34:0] = { r_ff[30:0],a_ff[31:28]} + b_ff[34:0]; assign adder02_out[35:0] = { r_ff[31:0],a_ff[31:28]} + {b_ff[34:0],1'b0}; assign adder03_out[36:0] = { r_ff[32:0],a_ff[31:28]} + {b_ff[35:0],1'b0} + b_ff[36:0]; assign adder04_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[35:0],2'b0}; assign adder05_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[35:0],2'b0} + b_ff[37:0]; assign adder06_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[35:0],2'b0} + {b_ff[36:0],1'b0}; assign adder07_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[35:0],2'b0} + {b_ff[36:0],1'b0} + b_ff[37:0]; assign adder08_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[34:0],3'b0}; assign adder09_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[34:0],3'b0} + b_ff[37:0]; assign adder10_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[34:0],3'b0} + {b_ff[36:0],1'b0}; assign adder11_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[34:0],3'b0} + {b_ff[36:0],1'b0} + b_ff[37:0]; assign adder12_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[34:0],3'b0} + {b_ff[35:0],2'b0}; assign adder13_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[34:0],3'b0} + {b_ff[35:0],2'b0} + b_ff[37:0]; assign adder14_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[34:0],3'b0} + {b_ff[35:0],2'b0} + {b_ff[36:0],1'b0}; assign adder15_out[37:0] = {r_ff[32],r_ff[32:0],a_ff[31:28]} + {b_ff[34:0],3'b0} + {b_ff[35:0],2'b0} + {b_ff[36:0],1'b0} + b_ff[37:0]; assign quotient_raw[01] = (~adder01_out[34] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder01_out[34:0] == 35'b0) ); assign quotient_raw[02] = (~adder02_out[35] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder02_out[35:0] == 36'b0) ); assign quotient_raw[03] = (~adder03_out[36] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder03_out[36:0] == 37'b0) ); assign quotient_raw[04] = (~adder04_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder04_out[37:0] == 38'b0) ); assign quotient_raw[05] = (~adder05_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder05_out[37:0] == 38'b0) ); assign quotient_raw[06] = (~adder06_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder06_out[37:0] == 38'b0) ); assign quotient_raw[07] = (~adder07_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder07_out[37:0] == 38'b0) ); assign quotient_raw[08] = (~adder08_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder08_out[37:0] == 38'b0) ); assign quotient_raw[09] = (~adder09_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder09_out[37:0] == 38'b0) ); assign quotient_raw[10] = (~adder10_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder10_out[37:0] == 38'b0) ); assign quotient_raw[11] = (~adder11_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder11_out[37:0] == 38'b0) ); assign quotient_raw[12] = (~adder12_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder12_out[37:0] == 38'b0) ); assign quotient_raw[13] = (~adder13_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder13_out[37:0] == 38'b0) ); assign quotient_raw[14] = (~adder14_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder14_out[37:0] == 38'b0) ); assign quotient_raw[15] = (~adder15_out[37] ^ dividend_sign_ff) | ( (a_ff[27:0] == 28'b0) & (adder15_out[37:0] == 38'b0) ); assign quotient_new[0] = ( quotient_raw[15:01] == 15'b000_0000_0000_0001 ) | // 1 ( quotient_raw[15:03] == 13'b000_0000_0000_01 ) | // 3 ( quotient_raw[15:05] == 11'b000_0000_0001 ) | // 5 ( quotient_raw[15:07] == 9'b000_0000_01 ) | // 7 ( quotient_raw[15:09] == 7'b000_0001 ) | // 9 ( quotient_raw[15:11] == 5'b000_01 ) | // 11 ( quotient_raw[15:13] == 3'b001 ) | // 13 ( quotient_raw[ 15] == 1'b1 ); // 15 assign quotient_new[1] = ( quotient_raw[15:02] == 14'b000_0000_0000_001 ) | // 2 ( quotient_raw[15:03] == 13'b000_0000_0000_01 ) | // 3 ( quotient_raw[15:06] == 10'b000_0000_001 ) | // 6 ( quotient_raw[15:07] == 9'b000_0000_01 ) | // 7 ( quotient_raw[15:10] == 6'b000_001 ) | // 10 ( quotient_raw[15:11] == 5'b000_01 ) | // 11 ( quotient_raw[15:14] == 2'b01 ) | // 14 ( quotient_raw[ 15] == 1'b1 ); // 15 assign quotient_new[2] = ( quotient_raw[15:04] == 12'b000_0000_0000_1 ) | // 4 ( quotient_raw[15:05] == 11'b000_0000_0001 ) | // 5 ( quotient_raw[15:06] == 10'b000_0000_001 ) | // 6 ( quotient_raw[15:07] == 9'b000_0000_01 ) | // 7 ( quotient_raw[15:12] == 4'b000_1 ) | // 12 ( quotient_raw[15:13] == 3'b001 ) | // 13 ( quotient_raw[15:14] == 2'b01 ) | // 14 ( quotient_raw[ 15] == 1'b1 ); // 15 assign quotient_new[3] = ( quotient_raw[15:08] == 8'b000_0000_1 ) | // 8 ( quotient_raw[15:09] == 7'b000_0001 ) | // 9 ( quotient_raw[15:10] == 6'b000_001 ) | // 10 ( quotient_raw[15:11] == 5'b000_01 ) | // 11 ( quotient_raw[15:12] == 4'b000_1 ) | // 12 ( quotient_raw[15:13] == 3'b001 ) | // 13 ( quotient_raw[15:14] == 2'b01 ) | // 14 ( quotient_raw[ 15] == 1'b1 ); // 15 assign twos_comp_b_sel = valid_ff & ~(dividend_sign_ff ^ divisor_sign_ff); assign twos_comp_q_sel = ~valid_ff & ~rem_ff & (dividend_sign_ff ^ divisor_sign_ff) & ~by_zero_case_ff; assign twos_comp_in[31:0] = ( {32{twos_comp_q_sel}} & q_ff[31:0] ) | ( {32{twos_comp_b_sel}} & b_ff[31:0] ); rvtwoscomp #(32) i_twos_comp (.din(twos_comp_in[31:0]), .dout(twos_comp_out[31:0])); assign valid_out = finish_ff & ~cancel; assign data_out[31:0] = ( {32{~rem_ff & ~twos_comp_q_sel}} & q_ff[31:0] ) | ( {32{ rem_ff }} & r_ff[31:0] ) | ( {32{ twos_comp_q_sel}} & twos_comp_out[31:0] ); // *** *** *** START : SMALLNUM {{ assign smallnum_case = ( (a_ff[31:4] == 28'b0) & (b_ff[31:4] == 28'b0) & ~by_zero_case & ~rem_ff & valid_ff & ~cancel) | ( (a_ff[31:0] == 32'b0) & ~by_zero_case & ~rem_ff & valid_ff & ~cancel); assign smallnum[3] = ( a_ff[3] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ); assign smallnum[2] = ( a_ff[3] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[2] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & ~b_ff[2] ); assign smallnum[1] = ( a_ff[2] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[1] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & ~b_ff[3] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & ~a_ff[2] & ~b_ff[3] & ~b_ff[2] & b_ff[1] & b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & ~b_ff[0]) | ( a_ff[3] & a_ff[2] & ~b_ff[3] & b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[1] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[2] ); assign smallnum[0] = ( a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & a_ff[0] & ~b_ff[3] & b_ff[1] & b_ff[0]) | ( a_ff[2] & ~b_ff[3] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[1] & ~b_ff[3] & ~b_ff[2] & ~b_ff[0]) | ( a_ff[0] & ~b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | (~a_ff[3] & a_ff[2] & ~a_ff[1] & ~b_ff[3] & ~b_ff[2] & b_ff[1] & b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & ~b_ff[0]) | ( a_ff[3] & ~b_ff[2] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & ~a_ff[2] & ~b_ff[3] & b_ff[2] & b_ff[1] ) | (~a_ff[3] & a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[2] & ~b_ff[1] ) | (~a_ff[3] & a_ff[2] & a_ff[0] & ~b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & ~a_ff[1] & ~b_ff[3] & b_ff[2] & b_ff[0]) | ( ~a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & ~b_ff[1] & ~b_ff[0]) | ( a_ff[3] & a_ff[1] & ~b_ff[2] & ~b_ff[0]) | (~a_ff[3] & a_ff[2] & a_ff[1] & a_ff[0] & ~b_ff[3] & b_ff[2] ) | ( a_ff[3] & a_ff[2] & b_ff[3] & ~b_ff[2] ) | ( a_ff[3] & a_ff[1] & b_ff[3] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & a_ff[0] & ~b_ff[2] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[1] & ~b_ff[3] & b_ff[2] & b_ff[1] & b_ff[0]) | ( a_ff[3] & a_ff[2] & a_ff[1] & b_ff[3] & ~b_ff[0]) | ( a_ff[3] & a_ff[2] & a_ff[1] & b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & a_ff[2] & a_ff[0] & b_ff[3] & ~b_ff[1] ) | ( a_ff[3] & ~a_ff[2] & a_ff[1] & ~b_ff[3] & b_ff[1] ) | ( a_ff[3] & a_ff[1] & a_ff[0] & ~b_ff[2] ) | ( a_ff[3] & a_ff[2] & a_ff[1] & a_ff[0] & b_ff[3] ); // *** *** *** END : SMALLNUM }} // *** *** *** Start : Short Q {{ assign shortq_dividend[32:0] = {dividend_sign_ff,a_ff[31:0]}; logic [5:0] dw_a_enc; logic [5:0] dw_b_enc; logic [6:0] dw_shortq_raw; el2_exu_div_cls i_a_cls ( .operand ( shortq_dividend[32:0] ), .cls ( dw_a_enc[4:0] )); el2_exu_div_cls i_b_cls ( .operand ( b_ff[32:0] ), .cls ( dw_b_enc[4:0] )); assign dw_a_enc[5] = 1'b0; assign dw_b_enc[5] = 1'b0; assign dw_shortq_raw[6:0] = {1'b0,dw_b_enc[5:0]} - {1'b0,dw_a_enc[5:0]} + 7'd1; assign shortq[5:0] = dw_shortq_raw[6] ? 6'd0 : dw_shortq_raw[5:0]; assign shortq_enable = valid_ff & ~shortq[5] & ~(shortq[4:2] == 3'b111) & ~cancel; assign shortq_decode[4:0] = ( {5{shortq[4:0] == 5'd31}} & 5'd00) | ( {5{shortq[4:0] == 5'd30}} & 5'd00) | ( {5{shortq[4:0] == 5'd29}} & 5'd00) | ( {5{shortq[4:0] == 5'd28}} & 5'd00) | ( {5{shortq[4:0] == 5'd27}} & 5'd04) | ( {5{shortq[4:0] == 5'd26}} & 5'd04) | ( {5{shortq[4:0] == 5'd25}} & 5'd04) | ( {5{shortq[4:0] == 5'd24}} & 5'd04) | ( {5{shortq[4:0] == 5'd23}} & 5'd08) | ( {5{shortq[4:0] == 5'd22}} & 5'd08) | ( {5{shortq[4:0] == 5'd21}} & 5'd08) | ( {5{shortq[4:0] == 5'd20}} & 5'd08) | ( {5{shortq[4:0] == 5'd19}} & 5'd12) | ( {5{shortq[4:0] == 5'd18}} & 5'd12) | ( {5{shortq[4:0] == 5'd17}} & 5'd12) | ( {5{shortq[4:0] == 5'd16}} & 5'd12) | ( {5{shortq[4:0] == 5'd15}} & 5'd16) | ( {5{shortq[4:0] == 5'd14}} & 5'd16) | ( {5{shortq[4:0] == 5'd13}} & 5'd16) | ( {5{shortq[4:0] == 5'd12}} & 5'd16) | ( {5{shortq[4:0] == 5'd11}} & 5'd20) | ( {5{shortq[4:0] == 5'd10}} & 5'd20) | ( {5{shortq[4:0] == 5'd09}} & 5'd20) | ( {5{shortq[4:0] == 5'd08}} & 5'd20) | ( {5{shortq[4:0] == 5'd07}} & 5'd24) | ( {5{shortq[4:0] == 5'd06}} & 5'd24) | ( {5{shortq[4:0] == 5'd05}} & 5'd24) | ( {5{shortq[4:0] == 5'd04}} & 5'd24) | ( {5{shortq[4:0] == 5'd03}} & 5'd28) | ( {5{shortq[4:0] == 5'd02}} & 5'd28) | ( {5{shortq[4:0] == 5'd01}} & 5'd28) | ( {5{shortq[4:0] == 5'd00}} & 5'd28); assign shortq_shift[4:0] = ~shortq_enable ? 5'd0 : shortq_decode[4:0]; // *** *** *** End : Short Q }} endmodule // el2_exu_div_new_4bit_fullshortq // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * module el2_exu_div_cls ( input logic [32:0] operand, output logic [4:0] cls // Count leading sign bits - "n" format ignoring [32] ); logic [4:0] cls_zeros; logic [4:0] cls_ones; assign cls_zeros[4:0] = ({5{operand[31] == { 1'b1} }} & 5'd00) | ({5{operand[31:30] == {{ 1{1'b0}},1'b1} }} & 5'd01) | ({5{operand[31:29] == {{ 2{1'b0}},1'b1} }} & 5'd02) | ({5{operand[31:28] == {{ 3{1'b0}},1'b1} }} & 5'd03) | ({5{operand[31:27] == {{ 4{1'b0}},1'b1} }} & 5'd04) | ({5{operand[31:26] == {{ 5{1'b0}},1'b1} }} & 5'd05) | ({5{operand[31:25] == {{ 6{1'b0}},1'b1} }} & 5'd06) | ({5{operand[31:24] == {{ 7{1'b0}},1'b1} }} & 5'd07) | ({5{operand[31:23] == {{ 8{1'b0}},1'b1} }} & 5'd08) | ({5{operand[31:22] == {{ 9{1'b0}},1'b1} }} & 5'd09) | ({5{operand[31:21] == {{10{1'b0}},1'b1} }} & 5'd10) | ({5{operand[31:20] == {{11{1'b0}},1'b1} }} & 5'd11) | ({5{operand[31:19] == {{12{1'b0}},1'b1} }} & 5'd12) | ({5{operand[31:18] == {{13{1'b0}},1'b1} }} & 5'd13) | ({5{operand[31:17] == {{14{1'b0}},1'b1} }} & 5'd14) | ({5{operand[31:16] == {{15{1'b0}},1'b1} }} & 5'd15) | ({5{operand[31:15] == {{16{1'b0}},1'b1} }} & 5'd16) | ({5{operand[31:14] == {{17{1'b0}},1'b1} }} & 5'd17) | ({5{operand[31:13] == {{18{1'b0}},1'b1} }} & 5'd18) | ({5{operand[31:12] == {{19{1'b0}},1'b1} }} & 5'd19) | ({5{operand[31:11] == {{20{1'b0}},1'b1} }} & 5'd20) | ({5{operand[31:10] == {{21{1'b0}},1'b1} }} & 5'd21) | ({5{operand[31:09] == {{22{1'b0}},1'b1} }} & 5'd22) | ({5{operand[31:08] == {{23{1'b0}},1'b1} }} & 5'd23) | ({5{operand[31:07] == {{24{1'b0}},1'b1} }} & 5'd24) | ({5{operand[31:06] == {{25{1'b0}},1'b1} }} & 5'd25) | ({5{operand[31:05] == {{26{1'b0}},1'b1} }} & 5'd26) | ({5{operand[31:04] == {{27{1'b0}},1'b1} }} & 5'd27) | ({5{operand[31:03] == {{28{1'b0}},1'b1} }} & 5'd28) | ({5{operand[31:02] == {{29{1'b0}},1'b1} }} & 5'd29) | ({5{operand[31:01] == {{30{1'b0}},1'b1} }} & 5'd30) | ({5{operand[31:00] == {{31{1'b0}},1'b1} }} & 5'd31) | ({5{operand[31:00] == {{32{1'b0}} } }} & 5'd00); // Don't care case as it will be handled as special case assign cls_ones[4:0] = ({5{operand[31:30] == {{ 1{1'b1}},1'b0} }} & 5'd00) | ({5{operand[31:29] == {{ 2{1'b1}},1'b0} }} & 5'd01) | ({5{operand[31:28] == {{ 3{1'b1}},1'b0} }} & 5'd02) | ({5{operand[31:27] == {{ 4{1'b1}},1'b0} }} & 5'd03) | ({5{operand[31:26] == {{ 5{1'b1}},1'b0} }} & 5'd04) | ({5{operand[31:25] == {{ 6{1'b1}},1'b0} }} & 5'd05) | ({5{operand[31:24] == {{ 7{1'b1}},1'b0} }} & 5'd06) | ({5{operand[31:23] == {{ 8{1'b1}},1'b0} }} & 5'd07) | ({5{operand[31:22] == {{ 9{1'b1}},1'b0} }} & 5'd08) | ({5{operand[31:21] == {{10{1'b1}},1'b0} }} & 5'd09) | ({5{operand[31:20] == {{11{1'b1}},1'b0} }} & 5'd10) | ({5{operand[31:19] == {{12{1'b1}},1'b0} }} & 5'd11) | ({5{operand[31:18] == {{13{1'b1}},1'b0} }} & 5'd12) | ({5{operand[31:17] == {{14{1'b1}},1'b0} }} & 5'd13) | ({5{operand[31:16] == {{15{1'b1}},1'b0} }} & 5'd14) | ({5{operand[31:15] == {{16{1'b1}},1'b0} }} & 5'd15) | ({5{operand[31:14] == {{17{1'b1}},1'b0} }} & 5'd16) | ({5{operand[31:13] == {{18{1'b1}},1'b0} }} & 5'd17) | ({5{operand[31:12] == {{19{1'b1}},1'b0} }} & 5'd18) | ({5{operand[31:11] == {{20{1'b1}},1'b0} }} & 5'd19) | ({5{operand[31:10] == {{21{1'b1}},1'b0} }} & 5'd20) | ({5{operand[31:09] == {{22{1'b1}},1'b0} }} & 5'd21) | ({5{operand[31:08] == {{23{1'b1}},1'b0} }} & 5'd22) | ({5{operand[31:07] == {{24{1'b1}},1'b0} }} & 5'd23) | ({5{operand[31:06] == {{25{1'b1}},1'b0} }} & 5'd24) | ({5{operand[31:05] == {{26{1'b1}},1'b0} }} & 5'd25) | ({5{operand[31:04] == {{27{1'b1}},1'b0} }} & 5'd26) | ({5{operand[31:03] == {{28{1'b1}},1'b0} }} & 5'd27) | ({5{operand[31:02] == {{29{1'b1}},1'b0} }} & 5'd28) | ({5{operand[31:01] == {{30{1'b1}},1'b0} }} & 5'd29) | ({5{operand[31:00] == {{31{1'b1}},1'b0} }} & 5'd30) | ({5{operand[31:00] == {{32{1'b1}} } }} & 5'd31); assign cls[4:0] = operand[32] ? cls_ones[4:0] : cls_zeros[4:0]; endmodule // el2_exu_div_cls ================================================ FILE: design/exu/el2_exu_mul_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. module el2_exu_mul_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Top level clock input logic rst_l, // Reset // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Scan mode /*pragma coverage on*/ input el2_mul_pkt_t mul_p, // {Valid, RS1 signed operand, RS2 signed operand, Select low 32-bits of result} input logic [31:0] rs1_in, // A operand input logic [31:0] rs2_in, // B operand output logic [31:0] result_x // Result ); logic mul_x_enable; logic bit_x_enable; logic signed [32:0] rs1_ext_in; logic signed [32:0] rs2_ext_in; logic [65:0] prod_x; logic low_x; // *** Start - BitManip *** logic bitmanip_sel_d; logic bitmanip_sel_x; logic [31:0] bitmanip_d; logic [31:0] bitmanip_x; // ZBE logic ap_bcompress; logic ap_bdecompress; // ZBC logic ap_clmul; logic ap_clmulh; logic ap_clmulr; // ZBP logic ap_grev; logic ap_gorc; logic ap_shfl; logic ap_unshfl; logic ap_xperm_n; logic ap_xperm_b; logic ap_xperm_h; // ZBR logic ap_crc32_b; logic ap_crc32_h; logic ap_crc32_w; logic ap_crc32c_b; logic ap_crc32c_h; logic ap_crc32c_w; // ZBF logic ap_bfp; if (pt.BITMANIP_ZBE == 1) begin assign ap_bcompress = mul_p.bcompress; assign ap_bdecompress = mul_p.bdecompress; end else begin assign ap_bcompress = 1'b0; assign ap_bdecompress = 1'b0; end if (pt.BITMANIP_ZBC == 1) begin assign ap_clmul = mul_p.clmul; assign ap_clmulh = mul_p.clmulh; assign ap_clmulr = mul_p.clmulr; end else begin assign ap_clmul = 1'b0; assign ap_clmulh = 1'b0; assign ap_clmulr = 1'b0; end if (pt.BITMANIP_ZBP == 1) begin assign ap_grev = mul_p.grev; assign ap_gorc = mul_p.gorc; assign ap_shfl = mul_p.shfl; assign ap_unshfl = mul_p.unshfl; assign ap_xperm_n = mul_p.xperm_n; assign ap_xperm_b = mul_p.xperm_b; assign ap_xperm_h = mul_p.xperm_h; end else begin assign ap_grev = 1'b0; assign ap_gorc = 1'b0; assign ap_shfl = 1'b0; assign ap_unshfl = 1'b0; assign ap_xperm_n = 1'b0; assign ap_xperm_b = 1'b0; assign ap_xperm_h = 1'b0; end if (pt.BITMANIP_ZBR == 1) begin assign ap_crc32_b = mul_p.crc32_b; assign ap_crc32_h = mul_p.crc32_h; assign ap_crc32_w = mul_p.crc32_w; assign ap_crc32c_b = mul_p.crc32c_b; assign ap_crc32c_h = mul_p.crc32c_h; assign ap_crc32c_w = mul_p.crc32c_w; end else begin assign ap_crc32_b = 1'b0; assign ap_crc32_h = 1'b0; assign ap_crc32_w = 1'b0; assign ap_crc32c_b = 1'b0; assign ap_crc32c_h = 1'b0; assign ap_crc32c_w = 1'b0; end if (pt.BITMANIP_ZBF == 1) begin assign ap_bfp = mul_p.bfp; end else begin assign ap_bfp = 1'b0; end // *** End - BitManip *** assign mul_x_enable = mul_p.valid; assign bit_x_enable = mul_p.valid; assign rs1_ext_in[32] = mul_p.rs1_sign & rs1_in[31]; assign rs2_ext_in[32] = mul_p.rs2_sign & rs2_in[31]; assign rs1_ext_in[31:0] = rs1_in[31:0]; assign rs2_ext_in[31:0] = rs2_in[31:0]; // --------------------------- Multiply ---------------------------------- logic signed [32:0] rs1_x; logic signed [32:0] rs2_x; rvdffe #(34) i_a_x_ff (.*, .clk(clk), .din({mul_p.low,rs1_ext_in[32:0]}), .dout({low_x,rs1_x[32:0]}), .en(mul_x_enable)); rvdffe #(33) i_b_x_ff (.*, .clk(clk), .din( rs2_ext_in[32:0] ), .dout( rs2_x[32:0] ), .en(mul_x_enable)); assign prod_x[65:0] = rs1_x * rs2_x; // * * * * * * * * * * * * * * * * * * BitManip : BCOMPRESS, BDECOMPRESS * * * * * * * * * * * * * // *** BCOMPRESS == "gather" *** logic [31:0] bcompress_d; logic bcompress_test_bit_d; integer bcompress_i, bcompress_j; always_comb begin bcompress_j = 0; bcompress_test_bit_d = 1'b0; bcompress_d[31:0] = 32'b0; for (bcompress_i=0; bcompress_i<32; bcompress_i++) begin bcompress_test_bit_d = rs2_in[bcompress_i]; if (bcompress_test_bit_d) begin bcompress_d[bcompress_j] = rs1_in[bcompress_i]; bcompress_j = bcompress_j + 1; end // IF bcompress_test_bit end // FOR bcompress_i end // ALWAYS_COMB // *** BDECOMPRESS == "scatter" *** logic [31:0] bdecompress_d; logic bdecompress_test_bit_d; integer bdecompress_i, bdecompress_j; always_comb begin bdecompress_j = 0; bdecompress_test_bit_d = 1'b0; bdecompress_d[31:0] = 32'b0; for (bdecompress_i=0; bdecompress_i<32; bdecompress_i++) begin bdecompress_test_bit_d = rs2_in[bdecompress_i]; if (bdecompress_test_bit_d) begin bdecompress_d[bdecompress_i] = rs1_in[bdecompress_j]; bdecompress_j = bdecompress_j + 1; end // IF bdecompress_test_bit end // FOR bdecompress_i end // ALWAYS_COMB // * * * * * * * * * * * * * * * * * * BitManip : CLMUL, CLMULH, CLMULR * * * * * * * * * * * * * logic [62:0] clmul_raw_d; assign clmul_raw_d[62:0] = ( {63{rs2_in[00]}} & {31'b0,rs1_in[31:0] } ) ^ ( {63{rs2_in[01]}} & {30'b0,rs1_in[31:0], 1'b0} ) ^ ( {63{rs2_in[02]}} & {29'b0,rs1_in[31:0], 2'b0} ) ^ ( {63{rs2_in[03]}} & {28'b0,rs1_in[31:0], 3'b0} ) ^ ( {63{rs2_in[04]}} & {27'b0,rs1_in[31:0], 4'b0} ) ^ ( {63{rs2_in[05]}} & {26'b0,rs1_in[31:0], 5'b0} ) ^ ( {63{rs2_in[06]}} & {25'b0,rs1_in[31:0], 6'b0} ) ^ ( {63{rs2_in[07]}} & {24'b0,rs1_in[31:0], 7'b0} ) ^ ( {63{rs2_in[08]}} & {23'b0,rs1_in[31:0], 8'b0} ) ^ ( {63{rs2_in[09]}} & {22'b0,rs1_in[31:0], 9'b0} ) ^ ( {63{rs2_in[10]}} & {21'b0,rs1_in[31:0],10'b0} ) ^ ( {63{rs2_in[11]}} & {20'b0,rs1_in[31:0],11'b0} ) ^ ( {63{rs2_in[12]}} & {19'b0,rs1_in[31:0],12'b0} ) ^ ( {63{rs2_in[13]}} & {18'b0,rs1_in[31:0],13'b0} ) ^ ( {63{rs2_in[14]}} & {17'b0,rs1_in[31:0],14'b0} ) ^ ( {63{rs2_in[15]}} & {16'b0,rs1_in[31:0],15'b0} ) ^ ( {63{rs2_in[16]}} & {15'b0,rs1_in[31:0],16'b0} ) ^ ( {63{rs2_in[17]}} & {14'b0,rs1_in[31:0],17'b0} ) ^ ( {63{rs2_in[18]}} & {13'b0,rs1_in[31:0],18'b0} ) ^ ( {63{rs2_in[19]}} & {12'b0,rs1_in[31:0],19'b0} ) ^ ( {63{rs2_in[20]}} & {11'b0,rs1_in[31:0],20'b0} ) ^ ( {63{rs2_in[21]}} & {10'b0,rs1_in[31:0],21'b0} ) ^ ( {63{rs2_in[22]}} & { 9'b0,rs1_in[31:0],22'b0} ) ^ ( {63{rs2_in[23]}} & { 8'b0,rs1_in[31:0],23'b0} ) ^ ( {63{rs2_in[24]}} & { 7'b0,rs1_in[31:0],24'b0} ) ^ ( {63{rs2_in[25]}} & { 6'b0,rs1_in[31:0],25'b0} ) ^ ( {63{rs2_in[26]}} & { 5'b0,rs1_in[31:0],26'b0} ) ^ ( {63{rs2_in[27]}} & { 4'b0,rs1_in[31:0],27'b0} ) ^ ( {63{rs2_in[28]}} & { 3'b0,rs1_in[31:0],28'b0} ) ^ ( {63{rs2_in[29]}} & { 2'b0,rs1_in[31:0],29'b0} ) ^ ( {63{rs2_in[30]}} & { 1'b0,rs1_in[31:0],30'b0} ) ^ ( {63{rs2_in[31]}} & { rs1_in[31:0],31'b0} ); // * * * * * * * * * * * * * * * * * * BitManip : GREV * * * * * * * * * * * * * * * * * * // uint32_t grev32(uint32_t rs1, uint32_t rs2) // { // uint32_t x = rs1; // int shamt = rs2 & 31; // // if (shamt & 1) x = ( (x & 0x55555555) << 1) | ( (x & 0xAAAAAAAA) >> 1); // if (shamt & 2) x = ( (x & 0x33333333) << 2) | ( (x & 0xCCCCCCCC) >> 2); // if (shamt & 4) x = ( (x & 0x0F0F0F0F) << 4) | ( (x & 0xF0F0F0F0) >> 4); // if (shamt & 8) x = ( (x & 0x00FF00FF) << 8) | ( (x & 0xFF00FF00) >> 8); // if (shamt & 16) x = ( (x & 0x0000FFFF) << 16) | ( (x & 0xFFFF0000) >> 16); // // return x; // } logic [31:0] grev1_d; logic [31:0] grev2_d; logic [31:0] grev4_d; logic [31:0] grev8_d; logic [31:0] grev_d; assign grev1_d[31:0] = (rs2_in[0]) ? {rs1_in[30],rs1_in[31],rs1_in[28],rs1_in[29],rs1_in[26],rs1_in[27],rs1_in[24],rs1_in[25], rs1_in[22],rs1_in[23],rs1_in[20],rs1_in[21],rs1_in[18],rs1_in[19],rs1_in[16],rs1_in[17], rs1_in[14],rs1_in[15],rs1_in[12],rs1_in[13],rs1_in[10],rs1_in[11],rs1_in[08],rs1_in[09], rs1_in[06],rs1_in[07],rs1_in[04],rs1_in[05],rs1_in[02],rs1_in[03],rs1_in[00],rs1_in[01]} : rs1_in[31:0]; assign grev2_d[31:0] = (rs2_in[1]) ? {grev1_d[29:28],grev1_d[31:30],grev1_d[25:24],grev1_d[27:26], grev1_d[21:20],grev1_d[23:22],grev1_d[17:16],grev1_d[19:18], grev1_d[13:12],grev1_d[15:14],grev1_d[09:08],grev1_d[11:10], grev1_d[05:04],grev1_d[07:06],grev1_d[01:00],grev1_d[03:02]} : grev1_d[31:0]; assign grev4_d[31:0] = (rs2_in[2]) ? {grev2_d[27:24],grev2_d[31:28],grev2_d[19:16],grev2_d[23:20], grev2_d[11:08],grev2_d[15:12],grev2_d[03:00],grev2_d[07:04]} : grev2_d[31:0]; assign grev8_d[31:0] = (rs2_in[3]) ? {grev4_d[23:16],grev4_d[31:24],grev4_d[07:00],grev4_d[15:08]} : grev4_d[31:0]; assign grev_d[31:0] = (rs2_in[4]) ? {grev8_d[15:00],grev8_d[31:16]} : grev8_d[31:0]; // * * * * * * * * * * * * * * * * * * BitManip : GORC * * * * * * * * * * * * * * * * * * // uint32_t gorc32(uint32_t rs1, uint32_t rs2) // { // uint32_t x = rs1; // int shamt = rs2 & 31; // // if (shamt & 1) x |= ( (x & 0x55555555) << 1) | ( (x & 0xAAAAAAAA) >> 1); // if (shamt & 2) x |= ( (x & 0x33333333) << 2) | ( (x & 0xCCCCCCCC) >> 2); // if (shamt & 4) x |= ( (x & 0x0F0F0F0F) << 4) | ( (x & 0xF0F0F0F0) >> 4); // if (shamt & 8) x |= ( (x & 0x00FF00FF) << 8) | ( (x & 0xFF00FF00) >> 8); // if (shamt & 16) x |= ( (x & 0x0000FFFF) << 16) | ( (x & 0xFFFF0000) >> 16); // // return x; // } logic [31:0] gorc1_d; logic [31:0] gorc2_d; logic [31:0] gorc4_d; logic [31:0] gorc8_d; logic [31:0] gorc_d; assign gorc1_d[31:0] = ( {32{rs2_in[0]}} & {rs1_in[30],rs1_in[31],rs1_in[28],rs1_in[29],rs1_in[26],rs1_in[27],rs1_in[24],rs1_in[25], rs1_in[22],rs1_in[23],rs1_in[20],rs1_in[21],rs1_in[18],rs1_in[19],rs1_in[16],rs1_in[17], rs1_in[14],rs1_in[15],rs1_in[12],rs1_in[13],rs1_in[10],rs1_in[11],rs1_in[08],rs1_in[09], rs1_in[06],rs1_in[07],rs1_in[04],rs1_in[05],rs1_in[02],rs1_in[03],rs1_in[00],rs1_in[01]} ) | rs1_in[31:0]; assign gorc2_d[31:0] = ( {32{rs2_in[1]}} & {gorc1_d[29:28],gorc1_d[31:30],gorc1_d[25:24],gorc1_d[27:26], gorc1_d[21:20],gorc1_d[23:22],gorc1_d[17:16],gorc1_d[19:18], gorc1_d[13:12],gorc1_d[15:14],gorc1_d[09:08],gorc1_d[11:10], gorc1_d[05:04],gorc1_d[07:06],gorc1_d[01:00],gorc1_d[03:02]} ) | gorc1_d[31:0]; assign gorc4_d[31:0] = ( {32{rs2_in[2]}} & {gorc2_d[27:24],gorc2_d[31:28],gorc2_d[19:16],gorc2_d[23:20], gorc2_d[11:08],gorc2_d[15:12],gorc2_d[03:00],gorc2_d[07:04]} ) | gorc2_d[31:0]; assign gorc8_d[31:0] = ( {32{rs2_in[3]}} & {gorc4_d[23:16],gorc4_d[31:24],gorc4_d[07:00],gorc4_d[15:08]} ) | gorc4_d[31:0]; assign gorc_d[31:0] = ( {32{rs2_in[4]}} & {gorc8_d[15:00],gorc8_d[31:16]} ) | gorc8_d[31:0]; // * * * * * * * * * * * * * * * * * * BitManip : SHFL, UNSHLF * * * * * * * * * * * * * * * * * * // uint32_t shuffle32_stage (uint32_t src, uint32_t maskL, uint32_t maskR, int N) // { // uint32_t x = src & ~(maskL | maskR); // x |= ((src << N) & maskL) | ((src >> N) & maskR); // return x; // } // // // // uint32_t shfl32(uint32_t rs1, uint32_t rs2) // { // uint32_t x = rs1; // int shamt = rs2 & 15 // // if (shamt & 8) x = shuffle32_stage(x, 0x00ff0000, 0x0000ff00, 8); // if (shamt & 4) x = shuffle32_stage(x, 0x0f000f00, 0x00f000f0, 4); // if (shamt & 2) x = shuffle32_stage(x, 0x30303030, 0xc0c0c0c0, 2); // if (shamt & 1) x = shuffle32_stage(x, 0x44444444, 0x22222222, 1); // // return x; // } logic [31:0] shfl8_d; logic [31:0] shfl4_d; logic [31:0] shfl2_d; logic [31:0] shfl_d; assign shfl8_d[31:0] = (rs2_in[3]) ? {rs1_in[31:24],rs1_in[15:08],rs1_in[23:16],rs1_in[07:00]} : rs1_in[31:0]; assign shfl4_d[31:0] = (rs2_in[2]) ? {shfl8_d[31:28],shfl8_d[23:20],shfl8_d[27:24],shfl8_d[19:16], shfl8_d[15:12],shfl8_d[07:04],shfl8_d[11:08],shfl8_d[03:00]} : shfl8_d[31:0]; assign shfl2_d[31:0] = (rs2_in[1]) ? {shfl4_d[31:30],shfl4_d[27:26],shfl4_d[29:28],shfl4_d[25:24], shfl4_d[23:22],shfl4_d[19:18],shfl4_d[21:20],shfl4_d[17:16], shfl4_d[15:14],shfl4_d[11:10],shfl4_d[13:12],shfl4_d[09:08], shfl4_d[07:06],shfl4_d[03:02],shfl4_d[05:04],shfl4_d[01:00]} : shfl4_d[31:0]; assign shfl_d[31:0] = (rs2_in[0]) ? {shfl2_d[31],shfl2_d[29],shfl2_d[30],shfl2_d[28],shfl2_d[27],shfl2_d[25],shfl2_d[26],shfl2_d[24], shfl2_d[23],shfl2_d[21],shfl2_d[22],shfl2_d[20],shfl2_d[19],shfl2_d[17],shfl2_d[18],shfl2_d[16], shfl2_d[15],shfl2_d[13],shfl2_d[14],shfl2_d[12],shfl2_d[11],shfl2_d[09],shfl2_d[10],shfl2_d[08], shfl2_d[07],shfl2_d[05],shfl2_d[06],shfl2_d[04],shfl2_d[03],shfl2_d[01],shfl2_d[02],shfl2_d[00]} : shfl2_d[31:0]; // uint32_t unshfl32(uint32_t rs1, uint32_t rs2) // { // uint32_t x = rs1; // int shamt = rs2 & 15 // // if (shamt & 1) x = shuffle32_stage(x, 0x44444444, 0x22222222, 1); // if (shamt & 2) x = shuffle32_stage(x, 0x30303030, 0xc0c0c0c0, 2); // if (shamt & 4) x = shuffle32_stage(x, 0x0f000f00, 0x00f000f0, 4); // if (shamt & 8) x = shuffle32_stage(x, 0x00ff0000, 0x0000ff00, 8); // // return x; // } logic [31:0] unshfl1_d; logic [31:0] unshfl2_d; logic [31:0] unshfl4_d; logic [31:0] unshfl_d; assign unshfl1_d[31:0] = (rs2_in[0]) ? {rs1_in[31],rs1_in[29],rs1_in[30],rs1_in[28],rs1_in[27],rs1_in[25],rs1_in[26],rs1_in[24], rs1_in[23],rs1_in[21],rs1_in[22],rs1_in[20],rs1_in[19],rs1_in[17],rs1_in[18],rs1_in[16], rs1_in[15],rs1_in[13],rs1_in[14],rs1_in[12],rs1_in[11],rs1_in[09],rs1_in[10],rs1_in[08], rs1_in[07],rs1_in[05],rs1_in[06],rs1_in[04],rs1_in[03],rs1_in[01],rs1_in[02],rs1_in[00]} : rs1_in[31:0]; assign unshfl2_d[31:0] = (rs2_in[1]) ? {unshfl1_d[31:30],unshfl1_d[27:26],unshfl1_d[29:28],unshfl1_d[25:24], unshfl1_d[23:22],unshfl1_d[19:18],unshfl1_d[21:20],unshfl1_d[17:16], unshfl1_d[15:14],unshfl1_d[11:10],unshfl1_d[13:12],unshfl1_d[09:08], unshfl1_d[07:06],unshfl1_d[03:02],unshfl1_d[05:04],unshfl1_d[01:00]} : unshfl1_d[31:0]; assign unshfl4_d[31:0] = (rs2_in[2]) ? {unshfl2_d[31:28],unshfl2_d[23:20],unshfl2_d[27:24],unshfl2_d[19:16], unshfl2_d[15:12],unshfl2_d[07:04],unshfl2_d[11:08],unshfl2_d[03:00]} : unshfl2_d[31:0]; assign unshfl_d[31:0] = (rs2_in[3]) ? {unshfl4_d[31:24],unshfl4_d[15:08],unshfl4_d[23:16],unshfl4_d[07:00]} : unshfl4_d[31:0]; // * * * * * * * * * * * * * * * * * * BitManip : XPERM * * * * * * * * * * * * * * * * * // // These instructions operate on nibbles/bytes/half-words/words. // rs1 is a vector of data words and rs2 is a vector of indices into rs1. // The result of the instruction is the vector rs2 with each element replaced by the corresponding data word from rs1, // or zero then the index in rs2 is out of bounds. // // uint_xlen_t xperm(uint_xlen_t rs1, uint_xlen_t rs2, int sz_log2) // { // uint_xlen_t r = 0; // uint_xlen_t sz = 1LL << sz_log2; // uint_xlen_t mask = (1LL << sz) - 1; // for (int i = 0; i < XLEN; i += sz) // { uint_xlen_t pos = ((rs2 >> i) & mask) << sz_log2; // if (pos < XLEN) // r |= ((rs1 >> pos) & mask) << i; // } // return r; // } // // uint_xlen_t xperm_n (uint_xlen_t rs1, uint_xlen_t rs2) { return xperm(rs1, rs2, 2); } // uint_xlen_t xperm_b (uint_xlen_t rs1, uint_xlen_t rs2) { return xperm(rs1, rs2, 3); } // uint_xlen_t xperm_h (uint_xlen_t rs1, uint_xlen_t rs2) { return xperm(rs1, rs2, 4); } // uint_xlen_t xperm_w (uint_xlen_t rs1, uint_xlen_t rs2) { return xperm(rs1, rs2, 5); } Not part of RV32 // // The xperm.[nbhw] instructions can be implemented with an XLEN/4-lane nibble-wide crossbarswitch. // *** XPERM_B *** // XLEN = 32 // SZ_LOG2 = 3 // SZ = 4'd8; // MASK = ( 1 << 8 ) - 1 // = 8'hFF // integer xperm_b_i; // logic [31:0] xperm_b_r; // logic [3:0] xperm_b_sz; // logic [7:0] xperm_b_mask; // logic [31:0] xperm_b_pos; // // // assign xperm_b_sz[3:0] = 4'd8; // assign xperm_b_mask[7:0] = 8'hff; // // always_comb // begin // xperm_b_r[31:0] = 32'b0; // // for (xperm_b_i=0; xperm_b_i<32; xperm_b_i = xperm_b_i + xperm_b_sz) // This code did not work... // begin // xperm_b_pos[31:0] = ( (rs2_in[31:0] >> xperm_b_i) & {24'h0,xperm_b_mask[7:0]} ) << 3; // if (xperm_b_pos[31:0] < 32'd32) // xperm_b_r[31:0] = xperm_b_r[31:0] | ( ((rs1_in[31:0] >> xperm_b_pos[4:0]) & {24'h0,xperm_b_mask[7:0]}) << xperm_b_i ); // end // end logic [31:0] xperm_n; logic [31:0] xperm_b; logic [31:0] xperm_h; assign xperm_n[03:00] = { 4{ ~rs2_in[03] }} & 4'( (rs1_in[31:0] >> {rs2_in[02:00],2'b0}) & 4'hf ); // This is a 8:1 mux with qualified selects assign xperm_n[07:04] = { 4{ ~rs2_in[07] }} & 4'( (rs1_in[31:0] >> {rs2_in[06:04],2'b0}) & 4'hf ); assign xperm_n[11:08] = { 4{ ~rs2_in[11] }} & 4'( (rs1_in[31:0] >> {rs2_in[10:08],2'b0}) & 4'hf ); assign xperm_n[15:12] = { 4{ ~rs2_in[15] }} & 4'( (rs1_in[31:0] >> {rs2_in[14:12],2'b0}) & 4'hf ); assign xperm_n[19:16] = { 4{ ~rs2_in[19] }} & 4'( (rs1_in[31:0] >> {rs2_in[18:16],2'b0}) & 4'hf ); assign xperm_n[23:20] = { 4{ ~rs2_in[23] }} & 4'( (rs1_in[31:0] >> {rs2_in[22:20],2'b0}) & 4'hf ); assign xperm_n[27:24] = { 4{ ~rs2_in[27] }} & 4'( (rs1_in[31:0] >> {rs2_in[26:24],2'b0}) & 4'hf ); assign xperm_n[31:28] = { 4{ ~rs2_in[31] }} & 4'( (rs1_in[31:0] >> {rs2_in[30:28],2'b0}) & 4'hf ); assign xperm_b[07:00] = { 8{ ~(| rs2_in[07:02]) }} & 8'( (rs1_in[31:0] >> {rs2_in[01:00],3'b0}) & 8'hff ); // This is a 4:1 mux with qualified selects assign xperm_b[15:08] = { 8{ ~(| rs2_in[15:10]) }} & 8'( (rs1_in[31:0] >> {rs2_in[09:08],3'b0}) & 8'hff ); assign xperm_b[23:16] = { 8{ ~(| rs2_in[23:18]) }} & 8'( (rs1_in[31:0] >> {rs2_in[17:16],3'b0}) & 8'hff ); assign xperm_b[31:24] = { 8{ ~(| rs2_in[31:26]) }} & 8'( (rs1_in[31:0] >> {rs2_in[25:24],3'b0}) & 8'hff ); assign xperm_h[15:00] = {16{ ~(| rs2_in[15:01]) }} & 16'( (rs1_in[31:0] >> {rs2_in[00] ,4'b0}) & 16'hffff ); // This is a 2:1 mux with qualified selects assign xperm_h[31:16] = {16{ ~(| rs2_in[31:17]) }} & 16'( (rs1_in[31:0] >> {rs2_in[16] ,4'b0}) & 16'hffff ); // * * * * * * * * * * * * * * * * * * BitManip : CRC32, CRC32c * * * * * * * * * * * * * * * * * // *** computed from https: //crccalc.com *** // // "a" is 8'h61 = 8'b0110_0001 (8'h61 ^ 8'hff = 8'h9e) // // Input must first be XORed with 32'hffff_ffff // // // CRC32 // // Input Output Input Output // ----- -------- -------- -------- // "a" e8b7be43 ffffff9e 174841bc // "aa" 078a19d7 ffff9e9e f875e628 // "aaaa" ad98e545 9e9e9e9e 5267a1ba // // // // CRC32c // // Input Output Input Output // ----- -------- -------- -------- // "a" c1d04330 ffffff9e 3e2fbccf // "aa" f1f2dac2 ffff9e9e 0e0d253d // "aaaa" 6a52eeb0 9e9e9e9e 95ad114f logic crc32_all; logic [31:0] crc32_poly_rev; logic [31:0] crc32c_poly_rev; integer crc32_bi, crc32_hi, crc32_wi, crc32c_bi, crc32c_hi, crc32c_wi; logic [31:0] crc32_bd, crc32_hd, crc32_wd, crc32c_bd, crc32c_hd, crc32c_wd; assign crc32_all = ap_crc32_b | ap_crc32_h | ap_crc32_w | ap_crc32c_b | ap_crc32c_h | ap_crc32c_w; assign crc32_poly_rev[31:0] = 32'hEDB88320; // bit reverse of 32'h04C11DB7 assign crc32c_poly_rev[31:0] = 32'h82F63B78; // bit reverse of 32'h1EDC6F41 always_comb begin crc32_bd[31:0] = rs1_in[31:0]; for (crc32_bi=0; crc32_bi<8; crc32_bi++) begin crc32_bd[31:0] = (crc32_bd[31:0] >> 1) ^ (crc32_poly_rev[31:0] & {32{crc32_bd[0]}}); end // FOR crc32_bi end // ALWAYS_COMB always_comb begin crc32_hd[31:0] = rs1_in[31:0]; for (crc32_hi=0; crc32_hi<16; crc32_hi++) begin crc32_hd[31:0] = (crc32_hd[31:0] >> 1) ^ (crc32_poly_rev[31:0] & {32{crc32_hd[0]}}); end // FOR crc32_hi end // ALWAYS_COMB always_comb begin crc32_wd[31:0] = rs1_in[31:0]; for (crc32_wi=0; crc32_wi<32; crc32_wi++) begin crc32_wd[31:0] = (crc32_wd[31:0] >> 1) ^ (crc32_poly_rev[31:0] & {32{crc32_wd[0]}}); end // FOR crc32_wi end // ALWAYS_COMB always_comb begin crc32c_bd[31:0] = rs1_in[31:0]; for (crc32c_bi=0; crc32c_bi<8; crc32c_bi++) begin crc32c_bd[31:0] = (crc32c_bd[31:0] >> 1) ^ (crc32c_poly_rev[31:0] & {32{crc32c_bd[0]}}); end // FOR crc32c_bi end // ALWAYS_COMB always_comb begin crc32c_hd[31:0] = rs1_in[31:0]; for (crc32c_hi=0; crc32c_hi<16; crc32c_hi++) begin crc32c_hd[31:0] = (crc32c_hd[31:0] >> 1) ^ (crc32c_poly_rev[31:0] & {32{crc32c_hd[0]}}); end // FOR crc32c_hi end // ALWAYS_COMB always_comb begin crc32c_wd[31:0] = rs1_in[31:0]; for (crc32c_wi=0; crc32c_wi<32; crc32c_wi++) begin crc32c_wd[31:0] = (crc32c_wd[31:0] >> 1) ^ (crc32c_poly_rev[31:0] & {32{crc32c_wd[0]}}); end // FOR crc32c_wi end // ALWAYS_COMB // * * * * * * * * * * * * * * * * * * BitManip : BFP * * * * * * * * * * * * * * * * * * // uint_xlen_t bfp(uint_xlen_t rs1, uint_xlen_t rs2) // { // uint_xlen_t cfg = rs2 >> (XLEN/2); // if ((cfg >> 30) == 2) cfg = cfg >> 16; // int len = (cfg >> 8) & (XLEN/2-1); // int off = cfg & (XLEN-1); // len = len ? len : XLEN/2; // uint_xlen_t mask = slo(0, len) << off; // uint_xlen_t data = rs2 << off; // return (data & mask) | (rs1 & ~mask); logic [4:0] bfp_len; logic [4:0] bfp_off; logic [31:0] bfp_len_mask_; logic [31:0] bfp_off_mask_; logic [15:0] bfp_preshift_data; logic [31:0] bfp_shift_data; logic [31:0] bfp_shift_mask; logic [31:0] bfp_result_d; assign bfp_len[3:0] = rs2_in[27:24]; assign bfp_len[4] = (bfp_len[3:0] == 4'b0); // If LEN field is zero, then LEN=16 assign bfp_off[4:0] = rs2_in[20:16]; assign bfp_len_mask_[31:0] = 32'hffff_ffff << bfp_len[4:0]; assign bfp_off_mask_[31:0] = 32'hffff_ffff << bfp_off[4:0]; assign bfp_preshift_data[15:0]= rs2_in[15:0] & ~bfp_len_mask_[15:0]; assign bfp_shift_data[31:0] = {16'b0,bfp_preshift_data[15:0]} << bfp_off[4:0]; assign bfp_shift_mask[31:0] = (bfp_len_mask_[31:0] << bfp_off[4:0]) | ~bfp_off_mask_[31:0]; assign bfp_result_d[31:0] = bfp_shift_data[31:0] | (rs1_in[31:0] & bfp_shift_mask[31:0]); // * * * * * * * * * * * * * * * * * * BitManip : Common logic * * * * * * * * * * * * * * * * * * assign bitmanip_sel_d = ap_bcompress | ap_bdecompress | ap_clmul | ap_clmulh | ap_clmulr | ap_grev | ap_gorc | ap_shfl | ap_unshfl | crc32_all | ap_bfp | ap_xperm_n | ap_xperm_b | ap_xperm_h; assign bitmanip_d[31:0] = ( {32{ap_bcompress}} & bcompress_d[31:0] ) | ( {32{ap_bdecompress}} & bdecompress_d[31:0] ) | ( {32{ap_clmul}} & clmul_raw_d[31:0] ) | ( {32{ap_clmulh}} & {1'b0,clmul_raw_d[62:32]} ) | ( {32{ap_clmulr}} & clmul_raw_d[62:31] ) | ( {32{ap_grev}} & grev_d[31:0] ) | ( {32{ap_gorc}} & gorc_d[31:0] ) | ( {32{ap_shfl}} & shfl_d[31:0] ) | ( {32{ap_unshfl}} & unshfl_d[31:0] ) | ( {32{ap_crc32_b}} & crc32_bd[31:0] ) | ( {32{ap_crc32_h}} & crc32_hd[31:0] ) | ( {32{ap_crc32_w}} & crc32_wd[31:0] ) | ( {32{ap_crc32c_b}} & crc32c_bd[31:0] ) | ( {32{ap_crc32c_h}} & crc32c_hd[31:0] ) | ( {32{ap_crc32c_w}} & crc32c_wd[31:0] ) | ( {32{ap_bfp}} & bfp_result_d[31:0] ) | ( {32{ap_xperm_n}} & xperm_n[31:0] ) | ( {32{ap_xperm_b}} & xperm_b[31:0] ) | ( {32{ap_xperm_h}} & xperm_h[31:0] ); rvdffe #(33) i_bitmanip_ff (.*, .clk(clk), .din({bitmanip_sel_d,bitmanip_d[31:0]}), .dout({bitmanip_sel_x,bitmanip_x[31:0]}), .en(bit_x_enable)); assign result_x[31:0] = ( {32{~bitmanip_sel_x & ~low_x}} & prod_x[63:32] ) | ( {32{~bitmanip_sel_x & low_x}} & prod_x[31:0] ) | bitmanip_x[31:0]; endmodule // el2_exu_mul_ctl ================================================ FILE: design/flist ================================================ $RV_ROOT/design/el2_veer_wrapper.sv $RV_ROOT/design/el2_veer_lockstep.sv $RV_ROOT/design/el2_mem.sv $RV_ROOT/design/el2_pic_ctrl.sv $RV_ROOT/design/el2_veer.sv $RV_ROOT/design/el2_dma_ctrl.sv $RV_ROOT/design/el2_pmp.sv $RV_ROOT/design/ifu/el2_ifu_aln_ctl.sv $RV_ROOT/design/ifu/el2_ifu_compress_ctl.sv $RV_ROOT/design/ifu/el2_ifu_ifc_ctl.sv $RV_ROOT/design/ifu/el2_ifu_bp_ctl.sv $RV_ROOT/design/ifu/el2_ifu_ic_mem.sv $RV_ROOT/design/ifu/el2_ifu_mem_ctl.sv $RV_ROOT/design/ifu/el2_ifu_iccm_mem.sv $RV_ROOT/design/ifu/el2_ifu.sv $RV_ROOT/design/dec/el2_dec_decode_ctl.sv $RV_ROOT/design/dec/el2_dec_gpr_ctl.sv $RV_ROOT/design/dec/el2_dec_ib_ctl.sv $RV_ROOT/design/dec/el2_dec_pmp_ctl.sv $RV_ROOT/design/dec/el2_dec_tlu_ctl.sv $RV_ROOT/design/dec/el2_dec_trigger.sv $RV_ROOT/design/dec/el2_dec.sv $RV_ROOT/design/exu/el2_exu_alu_ctl.sv $RV_ROOT/design/exu/el2_exu_mul_ctl.sv $RV_ROOT/design/exu/el2_exu_div_ctl.sv $RV_ROOT/design/exu/el2_exu.sv $RV_ROOT/design/lsu/el2_lsu.sv $RV_ROOT/design/lsu/el2_lsu_clkdomain.sv $RV_ROOT/design/lsu/el2_lsu_addrcheck.sv $RV_ROOT/design/lsu/el2_lsu_lsc_ctl.sv $RV_ROOT/design/lsu/el2_lsu_stbuf.sv $RV_ROOT/design/lsu/el2_lsu_bus_buffer.sv $RV_ROOT/design/lsu/el2_lsu_bus_intf.sv $RV_ROOT/design/lsu/el2_lsu_ecc.sv $RV_ROOT/design/lsu/el2_lsu_dccm_mem.sv $RV_ROOT/design/lsu/el2_lsu_dccm_ctl.sv $RV_ROOT/design/lsu/el2_lsu_trigger.sv $RV_ROOT/design/dbg/el2_dbg.sv $RV_ROOT/design/dmi/dmi_mux.v $RV_ROOT/design/dmi/dmi_wrapper.v $RV_ROOT/design/dmi/dmi_jtag_to_core_sync.v $RV_ROOT/design/dmi/rvjtag_tap.v $RV_ROOT/design/lib/el2_lib.sv $RV_ROOT/design/lib/el2_mem_if.sv -v $RV_ROOT/design/lib/beh_lib.sv -v $RV_ROOT/design/lib/mem_lib.sv $RV_ROOT/design/lib/ahb_to_axi4.sv $RV_ROOT/design/lib/axi4_to_ahb.sv ================================================ FILE: design/flist.formal ================================================ #-*-dotf-*- $RV_ROOT/design/include/el2_def.sv +incdir+$RV_ROOT/design/lib +incdir+$RV_ROOT/design/include +incdir+$RV_ROOT/design/dmi //|+incdir+$SYNOPSYS_SYN_ROOT/dw/sim_ver //|-y $SYNOPSYS_SYN_ROOT/dw/sim_ver //| //|$SYNOPSYS_SYN_ROOT/dw/sim_ver/DW01_addsub.v //|$SYNOPSYS_SYN_ROOT/dw/sim_ver/DW_lzd.v //|$SYNOPSYS_SYN_ROOT/dw/sim_ver/DW_minmax.v //|$SYNOPSYS_SYN_ROOT/dw/sim_ver/DW02_mult.v +incdir+/wdc/apps/mentor/questa/formal/2019.2/share/MODIFIED/dw +incdir+/wdc/apps/mentor/questa/formal/2019.2/share/MODIFIED/dw/dw_datapath /wdc/apps/mentor/questa/formal/2019.2/share/MODIFIED/dw/dw.remodel.v $RV_ROOT/design/el2_veer_wrapper.sv $RV_ROOT/design/el2_veer_lockstep.sv $RV_ROOT/design/el2_mem.sv $RV_ROOT/design/el2_pic_ctrl.sv $RV_ROOT/design/el2_veer.sv $RV_ROOT/design/el2_dma_ctrl.sv $RV_ROOT/design/el2_pmp.sv $RV_ROOT/design/ifu/el2_ifu_aln_ctl.sv $RV_ROOT/design/ifu/el2_ifu_compress_ctl.sv $RV_ROOT/design/ifu/el2_ifu_ifc_ctl.sv $RV_ROOT/design/ifu/el2_ifu_bp_ctl.sv $RV_ROOT/design/ifu/el2_ifu_ic_mem.sv $RV_ROOT/design/ifu/el2_ifu_mem_ctl.sv $RV_ROOT/design/ifu/el2_ifu_iccm_mem.sv $RV_ROOT/design/ifu/el2_ifu.sv $RV_ROOT/design/dec/el2_dec_decode_ctl.sv $RV_ROOT/design/dec/el2_dec_gpr_ctl.sv $RV_ROOT/design/dec/el2_dec_ib_ctl.sv $RV_ROOT/design/dec/el2_dec_pmp_ctl.sv $RV_ROOT/design/dec/el2_dec_tlu_ctl.sv $RV_ROOT/design/dec/el2_dec_trigger.sv $RV_ROOT/design/dec/el2_dec.sv $RV_ROOT/design/exu/el2_exu_alu_ctl.sv $RV_ROOT/design/exu/el2_exu_mul_ctl.sv $RV_ROOT/design/exu/el2_exu_div_ctl.sv $RV_ROOT/design/exu/el2_exu.sv $RV_ROOT/design/lsu/el2_lsu.sv $RV_ROOT/design/lsu/el2_lsu_clkdomain.sv $RV_ROOT/design/lsu/el2_lsu_addrcheck.sv $RV_ROOT/design/lsu/el2_lsu_lsc_ctl.sv $RV_ROOT/design/lsu/el2_lsu_stbuf.sv $RV_ROOT/design/lsu/el2_lsu_bus_buffer.sv $RV_ROOT/design/lsu/el2_lsu_bus_intf.sv $RV_ROOT/design/lsu/el2_lsu_ecc.sv $RV_ROOT/design/lsu/el2_lsu_dccm_mem.sv $RV_ROOT/design/lsu/el2_lsu_dccm_ctl.sv $RV_ROOT/design/lsu/el2_lsu_trigger.sv $RV_ROOT/design/dbg/el2_dbg.sv $RV_ROOT/design/dmi/dmi_mux.v $RV_ROOT/design/dmi/dmi_wrapper.v $RV_ROOT/design/dmi/dmi_jtag_to_core_sync.v $RV_ROOT/design/dmi/rvjtag_tap.v $RV_ROOT/design/lib/el2_lib.sv $RV_ROOT/design/lib/el2_mem_if.sv $RV_ROOT/design/lib/beh_lib.sv $RV_ROOT/design/lib/mem_lib.sv $RV_ROOT/design/lib/ahb_to_axi4.sv $RV_ROOT/design/lib/axi4_to_ahb.sv ================================================ FILE: design/flist.lint ================================================ +libext+.v+.sv +define+RV_OPENSOURCE +incdir+$RV_ROOT/design/include +incdir+$RV_ROOT/design/lib +incdir+$RV_ROOT/design/include +incdir+$RV_ROOT/snapshots/default $RV_ROOT/snapshots/default/common_defines.vh $RV_ROOT/design/include/el2_def.sv $RV_ROOT/design/el2_veer_wrapper.sv $RV_ROOT/design/lib/el2_mem_if.sv $RV_ROOT/design/el2_mem.sv $RV_ROOT/design/el2_pic_ctrl.sv $RV_ROOT/design/el2_veer.sv $RV_ROOT/design/el2_dma_ctrl.sv $RV_ROOT/design/el2_pmp.sv $RV_ROOT/design/ifu/el2_ifu_aln_ctl.sv $RV_ROOT/design/ifu/el2_ifu_compress_ctl.sv $RV_ROOT/design/ifu/el2_ifu_ifc_ctl.sv $RV_ROOT/design/ifu/el2_ifu_bp_ctl.sv $RV_ROOT/design/ifu/el2_ifu_ic_mem.sv $RV_ROOT/design/ifu/el2_ifu_mem_ctl.sv $RV_ROOT/design/ifu/el2_ifu_iccm_mem.sv $RV_ROOT/design/ifu/el2_ifu.sv $RV_ROOT/design/dec/el2_dec_decode_ctl.sv $RV_ROOT/design/dec/el2_dec_gpr_ctl.sv $RV_ROOT/design/dec/el2_dec_ib_ctl.sv $RV_ROOT/design/dec/el2_dec_pmp_ctl.sv $RV_ROOT/design/dec/el2_dec_tlu_ctl.sv $RV_ROOT/design/dec/el2_dec_trigger.sv $RV_ROOT/design/dec/el2_dec.sv $RV_ROOT/design/exu/el2_exu_alu_ctl.sv $RV_ROOT/design/exu/el2_exu_mul_ctl.sv $RV_ROOT/design/exu/el2_exu_div_ctl.sv $RV_ROOT/design/exu/el2_exu.sv $RV_ROOT/design/lsu/el2_lsu.sv $RV_ROOT/design/lsu/el2_lsu_clkdomain.sv $RV_ROOT/design/lsu/el2_lsu_addrcheck.sv $RV_ROOT/design/lsu/el2_lsu_lsc_ctl.sv $RV_ROOT/design/lsu/el2_lsu_stbuf.sv $RV_ROOT/design/lsu/el2_lsu_bus_buffer.sv $RV_ROOT/design/lsu/el2_lsu_bus_intf.sv $RV_ROOT/design/lsu/el2_lsu_ecc.sv $RV_ROOT/design/lsu/el2_lsu_dccm_mem.sv $RV_ROOT/design/lsu/el2_lsu_dccm_ctl.sv $RV_ROOT/design/lsu/el2_lsu_trigger.sv $RV_ROOT/design/dbg/el2_dbg.sv $RV_ROOT/design/dmi/dmi_mux.v $RV_ROOT/design/dmi/dmi_wrapper.v $RV_ROOT/design/dmi/dmi_jtag_to_core_sync.v $RV_ROOT/design/dmi/rvjtag_tap.v $RV_ROOT/design/lib/el2_lib.sv $RV_ROOT/design/lib/beh_lib.sv ================================================ FILE: design/flist.questa ================================================ #-*-dotf-*- # $RV_ROOT/workspace/work/snapshots/default/common_defines.vh # $RV_ROOT/configs/snapshots/default/common_defines.vh $RV_ROOT/workspace/work/snapshots/default/common_defines.vh $RV_ROOT/design/include/el2_def.sv # +incdir+$RV_ROOT/workspace/work/snapshots/default # +incdir+$RV_ROOT/configs/snapshots/default +incdir+$RV_ROOT/workspace/work/snapshots/default +incdir+$RV_ROOT/design/lib +incdir+$RV_ROOT/design/include +incdir+$RV_ROOT/design/dmi +incdir+$SYNOPSYS_SYN_ROOT/dw/sim_ver -y $SYNOPSYS_SYN_ROOT/dw/sim_ver $RV_ROOT/design/el2_veer_wrapper.sv $RV_ROOT/design/el2_veer_lockstep.sv $RV_ROOT/design/el2_mem.sv $RV_ROOT/design/el2_pic_ctrl.sv $RV_ROOT/design/el2_veer.sv $RV_ROOT/design/el2_dma_ctrl.sv $RV_ROOT/design/el2_pmp.sv $RV_ROOT/design/ifu/el2_ifu_aln_ctl.sv $RV_ROOT/design/ifu/el2_ifu_compress_ctl.sv $RV_ROOT/design/ifu/el2_ifu_ifc_ctl.sv $RV_ROOT/design/ifu/el2_ifu_bp_ctl.sv $RV_ROOT/design/ifu/el2_ifu_ic_mem.sv $RV_ROOT/design/ifu/el2_ifu_mem_ctl.sv $RV_ROOT/design/ifu/el2_ifu_iccm_mem.sv $RV_ROOT/design/ifu/el2_ifu.sv $RV_ROOT/design/dec/el2_dec_decode_ctl.sv $RV_ROOT/design/dec/el2_dec_gpr_ctl.sv $RV_ROOT/design/dec/el2_dec_ib_ctl.sv $RV_ROOT/design/dec/el2_dec_pmp_ctl.sv $RV_ROOT/design/dec/el2_dec_tlu_ctl.sv $RV_ROOT/design/dec/el2_dec_trigger.sv $RV_ROOT/design/dec/el2_dec.sv $RV_ROOT/design/exu/el2_exu_alu_ctl.sv $RV_ROOT/design/exu/el2_exu_mul_ctl.sv $RV_ROOT/design/exu/el2_exu_div_ctl.sv $RV_ROOT/design/exu/el2_exu.sv $RV_ROOT/design/lsu/el2_lsu.sv $RV_ROOT/design/lsu/el2_lsu_clkdomain.sv $RV_ROOT/design/lsu/el2_lsu_addrcheck.sv $RV_ROOT/design/lsu/el2_lsu_lsc_ctl.sv $RV_ROOT/design/lsu/el2_lsu_stbuf.sv $RV_ROOT/design/lsu/el2_lsu_bus_buffer.sv $RV_ROOT/design/lsu/el2_lsu_bus_intf.sv $RV_ROOT/design/lsu/el2_lsu_ecc.sv $RV_ROOT/design/lsu/el2_lsu_dccm_mem.sv $RV_ROOT/design/lsu/el2_lsu_dccm_ctl.sv $RV_ROOT/design/lsu/el2_lsu_trigger.sv $RV_ROOT/design/dbg/el2_dbg.sv $RV_ROOT/design/dmi/dmi_mux.v $RV_ROOT/design/dmi/dmi_wrapper.v $RV_ROOT/design/dmi/dmi_jtag_to_core_sync.v $RV_ROOT/design/dmi/rvjtag_tap.v $RV_ROOT/design/lib/el2_lib.sv $RV_ROOT/design/lib/el2_mem_if.sv $RV_ROOT/design/lib/beh_lib.sv $RV_ROOT/design/lib/mem_lib.sv $RV_ROOT/design/lib/ahb_to_axi4.sv $RV_ROOT/design/lib/axi4_to_ahb.sv ================================================ FILE: design/ifu/el2_ifu.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** //******************************************************************************** // Function: Top level file for Icache, Fetch, Branch prediction & Aligner // BFF -> F1 -> F2 -> A //******************************************************************************** module el2_ifu import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic rst_l, // reset, active low input logic dec_i0_decode_d, // Valid instruction at D and not blocked input logic exu_flush_final, // flush, includes upper and lower input logic dec_tlu_i0_commit_cmt , // committed i0 input logic dec_tlu_flush_err_wb , // flush due to parity error. input logic dec_tlu_flush_noredir_wb, // don't fetch, validated with exu_flush_final input logic [31:1] exu_flush_path_final, // flush fetch address input logic [31:0] dec_tlu_mrac_ff ,// Side_effect , cacheable for each region input logic dec_tlu_fence_i_wb, // fence.i, invalidate icache, validated with exu_flush_final input logic dec_tlu_flush_leak_one_wb, // ignore bp for leak one fetches input logic dec_tlu_bpred_disable, // disable all branch prediction input logic dec_tlu_core_ecc_disable, // disable ecc checking and flagging input logic dec_tlu_force_halt, // force halt //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv */ /*pragma coverage off*/ output logic ifu_axi_awvalid, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid, output logic [31:0] ifu_axi_awaddr, output logic [3:0] ifu_axi_awregion, output logic [7:0] ifu_axi_awlen, output logic [2:0] ifu_axi_awsize, output logic [1:0] ifu_axi_awburst, output logic ifu_axi_awlock, output logic [3:0] ifu_axi_awcache, output logic [2:0] ifu_axi_awprot, output logic [3:0] ifu_axi_awqos, output logic ifu_axi_wvalid, output logic [63:0] ifu_axi_wdata, output logic [7:0] ifu_axi_wstrb, output logic ifu_axi_wlast, output logic ifu_axi_bready, /*pragma coverage on*/ // AXI Read Channels output logic ifu_axi_arvalid, input logic ifu_axi_arready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid, output logic [31:0] ifu_axi_araddr, output logic [3:0] ifu_axi_arregion, /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv */ /*pragma coverage off*/ output logic [7:0] ifu_axi_arlen, output logic [2:0] ifu_axi_arsize, output logic [1:0] ifu_axi_arburst, output logic ifu_axi_arlock, output logic [3:0] ifu_axi_arcache, output logic [2:0] ifu_axi_arprot, output logic [3:0] ifu_axi_arqos, /*pragma coverage on*/ input logic ifu_axi_rvalid, /* exclude signals that are tied to constant value in el2_ifu_mem_ctl.sv */ /*pragma coverage off*/ output logic ifu_axi_rready, /*pragma coverage on*/ input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid, input logic [63:0] ifu_axi_rdata, input logic [1:0] ifu_axi_rresp, input logic ifu_bus_clk_en, input logic dma_iccm_req, input logic [31:0] dma_mem_addr, input logic [2:0] dma_mem_sz, input logic dma_mem_write, input logic [63:0] dma_mem_wdata, input logic [2:0] dma_mem_tag, // DMA Buffer entry number input logic dma_iccm_stall_any, output logic iccm_dma_ecc_error, output logic iccm_dma_rvalid, output logic [63:0] iccm_dma_rdata, output logic [2:0] iccm_dma_rtag, // Tag of the DMA req output logic iccm_ready, output logic ifu_pmu_instr_aligned, output logic ifu_pmu_fetch_stall, output logic ifu_ic_error_start, // has all of the I$ ecc/parity for data/tag // I$ & ITAG Ports output logic [31:1] ic_rw_addr, // Read/Write addresss to the Icache. output logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en, // Icache write enable, when filling the Icache. output logic ic_rd_en, // Icache read enable. output logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC input logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [25:0] ictag_debug_rd_data,// Debug icache tag. output logic [70:0] ic_debug_wr_data, // Debug wr cache. output logic [70:0] ifu_ic_debug_rd_data, input logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, // input logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, output logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache. output logic ic_sel_premux_data, // Select the premux data. output logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. output logic ic_debug_rd_en, // Icache debug rd output logic ic_debug_wr_en, // Icache debug wr output logic ic_debug_tag_array, // Debug tag array output logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. output logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid, // Valid bits when accessing the Icache. One valid bit per way. F2 stage input logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, // Compare hits from Icache tags. Per way. F2 stage input logic ic_tag_perr, // Icache Tag parity error // ICCM ports output logic [pt.ICCM_BITS-1:1] iccm_rw_addr, // ICCM read/write address. output logic iccm_wren, // ICCM write enable (through the DMA) output logic iccm_rden, // ICCM read enable. output logic [77:0] iccm_wr_data, // ICCM write data. output logic [2:0] iccm_wr_size, // ICCM write location within DW. input logic [63:0] iccm_rd_data, // Data read from ICCM. input logic [77:0] iccm_rd_data_ecc, // Data + ECC read from ICCM. // ICCM ECC status output logic ifu_iccm_dma_rd_ecc_single_err, // This fetch has a single ICCM DMA ECC error. output logic ifu_iccm_rd_ecc_single_err, // This fetch has a single ICCM ECC error. output logic ifu_iccm_rd_ecc_double_err, // This fetch has a double ICCM ECC error. // Perf counter sigs output logic ifu_pmu_ic_miss, // ic miss output logic ifu_pmu_ic_hit, // ic hit output logic ifu_pmu_bus_error, // iside bus error output logic ifu_pmu_bus_busy, // iside bus busy output logic ifu_pmu_bus_trxn, // iside bus transactions output logic ifu_i0_icaf, // Instruction 0 access fault. From Aligner to Decode output logic [1:0] ifu_i0_icaf_type, // Instruction 0 access fault type output logic ifu_i0_valid, // Instruction 0 valid. From Aligner to Decode output logic ifu_i0_icaf_second, // Instruction 0 has access fault on second 2B of 4B inst output logic ifu_i0_dbecc, // Instruction 0 has double bit ecc error output logic iccm_dma_sb_error, // Single Bit ECC error from a DMA access output logic[31:0] ifu_i0_instr, // Instruction 0 . From Aligner to Decode output logic[31:1] ifu_i0_pc, // Instruction 0 pc. From Aligner to Decode output logic ifu_i0_pc4, // Instruction 0 is 4 byte. From Aligner to Decode output logic ifu_miss_state_idle, // There is no outstanding miss. Cache miss state is idle. output el2_br_pkt_t i0_brp, // Instruction 0 branch packet. From Aligner to Decode output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index output logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR output logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag output logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index input el2_predict_pkt_t exu_mp_pkt, // mispredict packet input logic [pt.BHT_GHR_SIZE-1:0] exu_mp_eghr, // execute ghr input logic [pt.BHT_GHR_SIZE-1:0] exu_mp_fghr, // Mispredict fghr input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_mp_index, // Mispredict index input logic [pt.BTB_BTAG_SIZE-1:0] exu_mp_btag, // Mispredict btag input el2_br_tlu_pkt_t dec_tlu_br0_r_pkt, // slot0 update/error pkt input logic [pt.BHT_GHR_SIZE-1:0] exu_i0_br_fghr_r, // fghr to bp input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_i0_br_index_r, // bp index input logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index, // Fully associt btb error index input dec_tlu_flush_lower_wb, output logic [15:0] ifu_i0_cinst, output logic [31:1] ifu_pmp_addr, input logic ifu_pmp_error, /// Icache debug input el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt , output logic ifu_ic_debug_rd_data_valid, output logic iccm_buf_correct_ecc, output logic iccm_correction_state, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); localparam TAGWIDTH = 2 ; localparam IDWIDTH = 2 ; logic ifu_fb_consume1, ifu_fb_consume2; logic [31:1] ifc_fetch_addr_f; logic [31:1] ifc_fetch_addr_bf; assign ifu_pmp_addr = ifc_fetch_addr_bf; logic [1:0] ifu_fetch_val; // valids on a 2B boundary, left justified [7] implies valid fetch logic [31:1] ifu_fetch_pc; // starting pc of fetch logic iccm_rd_ecc_single_err, iccm_dma_rd_ecc_single_err, ic_error_start; assign ifu_iccm_dma_rd_ecc_single_err = iccm_dma_rd_ecc_single_err; assign ifu_iccm_rd_ecc_single_err = iccm_rd_ecc_single_err; assign ifu_ic_error_start = ic_error_start; logic ic_write_stall; logic ic_dma_active; logic ifc_dma_access_ok; logic [1:0] ic_access_fault_f; logic [1:0] ic_access_fault_type_f; logic ifu_ic_mb_empty; logic ic_hit_f; logic [1:0] ifu_bp_way_f; // way indication; right justified logic ifu_bp_hit_taken_f; // kill next fetch; taken target found logic [31:1] ifu_bp_btb_target_f; // predicted target PC logic ifu_bp_inst_mask_f; // tell ic which valids to kill because of a taken branch; right justified logic [1:0] ifu_bp_hist1_f; // history counters for all 4 potential branches; right justified logic [1:0] ifu_bp_hist0_f; // history counters for all 4 potential branches; right justified logic [11:0] ifu_bp_poffset_f; // predicted target logic [1:0] ifu_bp_ret_f; // predicted ret ; right justified logic [1:0] ifu_bp_pc4_f; // pc4 indication; right justified logic [1:0] ifu_bp_valid_f; // branch valid, right justified logic [pt.BHT_GHR_SIZE-1:0] ifu_bp_fghr_f; logic [1:0] [$clog2(pt.BTB_SIZE)-1:0] ifu_bp_fa_index_f; logic [1:0] ic_fetch_val_f; logic [31:0] ic_data_f; logic [31:0] ifu_fetch_data_f; logic ifc_fetch_req_f; logic ifc_fetch_req_f_raw; logic iccm_dma_rd_ecc_double_err; logic [1:0] iccm_rd_ecc_double_err; // This fetch has an iccm double error. assign ifu_iccm_rd_ecc_double_err = |iccm_rd_ecc_double_err || |iccm_dma_rd_ecc_double_err; logic ifu_async_error_start; assign ifu_fetch_data_f[31:0] = ic_data_f[31:0]; assign ifu_fetch_val[1:0] = ic_fetch_val_f[1:0]; assign ifu_fetch_pc[31:1] = ifc_fetch_addr_f[31:1]; logic ifc_fetch_uncacheable_bf; // The fetch request is uncacheable space. BF stage logic ifc_fetch_req_bf; // Fetch request. Comes with the address. BF stage logic ifc_fetch_req_bf_raw; // Fetch request without some qualifications. Used for clock-gating. BF stage logic ifc_iccm_access_bf; // This request is to the ICCM. Do not generate misses to the bus. logic ifc_region_acc_fault_bf; // Access fault. in ICCM region but offset is outside defined ICCM. // fetch control el2_ifu_ifc_ctl #(.pt(pt)) ifc (.* ); // branch predictor if (pt.BTB_ENABLE==1) begin : bpred el2_ifu_bp_ctl #(.pt(pt)) bp (.*); end else begin : bpred assign ifu_bp_hit_taken_f = '0; // verif wires logic btb_wr_en_way0, btb_wr_en_way1,dec_tlu_error_wb; logic [16+pt.BTB_BTAG_SIZE:0] btb_wr_data; assign btb_wr_en_way0 = '0; assign btb_wr_en_way1 = '0; assign btb_wr_data = '0; assign dec_tlu_error_wb ='0; assign ifu_bp_inst_mask_f = 1'b1; end // aligner el2_ifu_aln_ctl #(.pt(pt)) aln ( .* ); // icache el2_ifu_mem_ctl #(.pt(pt)) mem_ctl (.*, .ic_data_f(ic_data_f[31:0]) ); // Performance debug info // // `ifdef DUMP_BTB_ON logic exu_mp_valid; // conditional branch mispredict logic exu_mp_way; // conditional branch mispredict logic exu_mp_ataken; // direction is actual taken logic exu_mp_boffset; // branch offsett logic exu_mp_pc4; // branch is a 4B inst logic exu_mp_call; // branch is a call inst logic exu_mp_ret; // branch is a ret inst logic exu_mp_ja; // branch is a jump always logic [1:0] exu_mp_hist; // new history logic [11:0] exu_mp_tgt; // target offset logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_mp_addr; // BTB/BHT address assign exu_mp_valid = exu_mp_pkt.misp; // conditional branch mispredict assign exu_mp_ataken = exu_mp_pkt.ataken; // direction is actual taken assign exu_mp_boffset = exu_mp_pkt.boffset; // branch offset assign exu_mp_pc4 = exu_mp_pkt.pc4; // branch is a 4B inst assign exu_mp_call = exu_mp_pkt.pcall; // branch is a call inst assign exu_mp_ret = exu_mp_pkt.pret; // branch is a ret inst assign exu_mp_ja = exu_mp_pkt.pja; // branch is a jump always assign exu_mp_way = exu_mp_pkt.way; // branch is a jump always assign exu_mp_hist[1:0] = exu_mp_pkt.hist[1:0]; // new history assign exu_mp_tgt[11:0] = exu_mp_pkt.toffset[11:0] ; // target offset assign exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = exu_mp_index[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ; // BTB/BHT address logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] btb_rd_addr_f; `define DEC `CPU_TOP.dec `define EXU `CPU_TOP.exu el2_btb_addr_hash f2hash(.pc(ifc_fetch_addr_f[pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]), .hash(btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO])); logic [31:0] mppc_ns, mppc; logic exu_flush_final_d1; assign mppc_ns[31:1] = `EXU.i0_flush_upper_x ? `EXU.exu_i0_pc_x : `EXU.dec_i0_pc_d; assign mppc_ns[0] = 1'b0; rvdff #(33) junk_ff (.*, .clk(active_clk), .din({mppc_ns[31:0], exu_flush_final}), .dout({mppc[31:0], exu_flush_final_d1})); logic tmp_bnk; assign tmp_bnk = bpred.bp.btb_sel_f[1]; always @(negedge clk) begin if(`DEC.tlu.mcyclel[31:0] == 32'h0000_0010) begin $display("BTB_CONFIG: %d",pt.BTB_SIZE); `ifndef BP_NOGSHARE $display("BHT_CONFIG: %d gshare: 1",pt.BHT_SIZE); `else $display("BHT_CONFIG: %d gshare: 0",pt.BHT_SIZE); `endif $display("RS_CONFIG: %d", pt.RET_STACK_SIZE); end if(exu_flush_final_d1 & ~(dec_tlu_br0_r_pkt.br_error | dec_tlu_br0_r_pkt.br_start_error) & (exu_mp_pkt.misp | exu_mp_pkt.ataken)) $display("%7d BTB_MP : index: %0h bank: %0h call: %b ret: %b ataken: %b hist: %h valid: %b tag: %h targ: %h eghr: %b pred: %b ghr_index: %h brpc: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha, exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO], 1'b0, exu_mp_call, exu_mp_ret, exu_mp_ataken, exu_mp_hist[1:0], exu_mp_valid, exu_mp_btag[pt.BTB_BTAG_SIZE-1:0], {exu_flush_path_final[31:1], 1'b0}, exu_mp_eghr[pt.BHT_GHR_SIZE-1:0], exu_mp_valid, bpred.bp.bht_wr_addr0, mppc[31:0], exu_mp_pkt.way); for(int i = 0; i < 8; i++) begin if(ifu_bp_valid_f[i] & ifc_fetch_req_f) $display("%7d BTB_HIT : index: %0h bank: %0h call: %b ret: %b taken: %b strength: %b tag: %h targ: %0h ghr: %4b ghr_index: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO],bpred.bp.btb_sel_f[1], bpred.bp.btb_rd_call_f, bpred.bp.btb_rd_ret_f, ifu_bp_hist1_f[tmp_bnk], ifu_bp_hist0_f[tmp_bnk], bpred.bp.fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0], {ifu_bp_btb_target_f[31:1], 1'b0}, bpred.bp.fghr[pt.BHT_GHR_SIZE-1:0], bpred.bp.bht_rd_addr_f, ifu_bp_way_f[tmp_bnk]); end if(dec_tlu_br0_r_pkt.valid & ~(dec_tlu_br0_r_pkt.br_error | dec_tlu_br0_r_pkt.br_start_error)) $display("%7d BTB_UPD0: ghr_index: %0h bank: %0h hist: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,bpred.bp.br0_hashed_wb[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO],{dec_tlu_br0_r_pkt.middle}, dec_tlu_br0_r_pkt.hist, dec_tlu_br0_r_pkt.way); if(dec_tlu_br0_r_pkt.br_error | dec_tlu_br0_r_pkt.br_start_error) $display("%7d BTB_ERR0: index: %0h bank: %0h start: %b rfpc: %h way: %h", `DEC.tlu.mcyclel[31:0]+32'ha,exu_i0_br_index_r[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO],1'b0, dec_tlu_br0_r_pkt.br_start_error, {exu_flush_path_final[31:1], 1'b0}, dec_tlu_br0_r_pkt.way); end // always @ (negedge clk) function [1:0] encode4_2; input [3:0] in; encode4_2[1] = in[3] | in[2]; encode4_2[0] = in[3] | in[1]; endfunction `endif endmodule // el2_ifu ================================================ FILE: design/ifu/el2_ifu_aln_ctl.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** //******************************************************************************** // Function: Instruction aligner //******************************************************************************** module el2_ifu_aln_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // Flop scan mode control /*pragma coverage on*/ input logic rst_l, // reset, active low input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic ifu_async_error_start, // ecc/parity related errors with current fetch - not sent down the pipe input logic [1:0] iccm_rd_ecc_double_err, // This fetch has a double ICCM ecc error. input logic [1:0] ic_access_fault_f, // Instruction access fault for the current fetch. input logic [1:0] ic_access_fault_type_f, // Instruction access fault types input logic exu_flush_final, // Flush from the pipeline. input logic dec_i0_decode_d, // Valid instruction at D-stage and not blocked input logic [31:0] ifu_fetch_data_f, // fetch data in memory format - not right justified input logic [1:0] ifu_fetch_val, // valids on a 2B boundary, right justified input logic [31:1] ifu_fetch_pc, // starting pc of fetch output logic ifu_i0_valid, // Instruction 0 is valid output logic ifu_i0_icaf, // Instruction 0 has access fault output logic [1:0] ifu_i0_icaf_type, // Instruction 0 access fault type output logic ifu_i0_icaf_second, // Instruction 0 has access fault on second 2B of 4B inst output logic ifu_i0_dbecc, // Instruction 0 has double bit ecc error output logic [31:0] ifu_i0_instr, // Instruction 0 output logic [31:1] ifu_i0_pc, // Instruction 0 PC output logic ifu_i0_pc4, output logic ifu_fb_consume1, // Consumed one buffer. To fetch control fetch for buffer mass balance output logic ifu_fb_consume2, // Consumed two buffers.To fetch control fetch for buffer mass balance input logic [pt.BHT_GHR_SIZE-1:0] ifu_bp_fghr_f, // fetch GHR input logic [31:1] ifu_bp_btb_target_f, // predicted RET target input logic [11:0] ifu_bp_poffset_f, // predicted target offset input logic [1:0] [$clog2(pt.BTB_SIZE)-1:0] ifu_bp_fa_index_f, // predicted branch index (fully associative option) input logic [1:0] ifu_bp_hist0_f, // history counters for all 4 potential branches, bit 1, right justified input logic [1:0] ifu_bp_hist1_f, // history counters for all 4 potential branches, bit 1, right justified input logic [1:0] ifu_bp_pc4_f, // pc4 indication, right justified input logic [1:0] ifu_bp_way_f, // way indication, right justified input logic [1:0] ifu_bp_valid_f, // branch valid, right justified input logic [1:0] ifu_bp_ret_f, // predicted ret indication, right justified output el2_br_pkt_t i0_brp, // Branch packet for I0. output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index output logic [pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR output logic [pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag output logic [$clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index output logic ifu_pmu_instr_aligned, // number of inst aligned this cycle output logic [15:0] ifu_i0_cinst // 16b compress inst for i0 ); logic ifvalid; logic shift_f1_f0, shift_f2_f0, shift_f2_f1; logic fetch_to_f0, fetch_to_f1, fetch_to_f2; logic [1:0] f2val_in, f2val; logic [1:0] f1val_in, f1val; logic [1:0] f0val_in, f0val; logic [1:0] sf1val, sf0val; logic [31:0] aligndata; logic first4B, first2B; logic [31:0] uncompress0; logic i0_shift; logic shift_2B, shift_4B; logic f1_shift_2B; logic f2_valid, sf1_valid, sf0_valid; logic [31:0] ifirst; logic [1:0] alignval; logic [31:1] firstpc, secondpc; logic [11:0] f1poffset; logic [11:0] f0poffset; logic [pt.BHT_GHR_SIZE-1:0] f1fghr; logic [pt.BHT_GHR_SIZE-1:0] f0fghr; logic [1:0] f1hist1; logic [1:0] f0hist1; logic [1:0] f1hist0; logic [1:0] f0hist0; logic [1:0][$clog2(pt.BTB_SIZE)-1:0] f0index, f1index, alignindex; logic [1:0] f1ictype; logic [1:0] f0ictype; logic [1:0] f1pc4; logic [1:0] f0pc4; logic [1:0] f1ret; logic [1:0] f0ret; logic [1:0] f1way; logic [1:0] f0way; logic [1:0] f1brend; logic [1:0] f0brend; logic [1:0] alignbrend; logic [1:0] alignpc4; logic [1:0] alignret; logic [1:0] alignway; logic [1:0] alignhist1; logic [1:0] alignhist0; logic [1:1] alignfromf1; logic i0_ends_f1; logic i0_br_start_error; logic [31:1] f1prett; logic [31:1] f0prett; logic [1:0] f1dbecc; logic [1:0] f0dbecc; logic [1:0] f1icaf; logic [1:0] f0icaf; logic [1:0] aligndbecc; logic [1:0] alignicaf; logic i0_brp_pc4; logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] firstpc_hash, secondpc_hash; logic [1:0] wrptr, wrptr_in; logic [1:0] rdptr, rdptr_in; logic [2:0] qwen; logic [31:0] q2,q1,q0; logic q2off_in, q2off; logic q1off_in, q1off; logic q0off_in, q0off; logic f0_shift_2B; logic [31:0] q0eff; logic [31:0] q0final; logic q0ptr; logic [1:0] q0sel; logic [31:0] q1eff; logic [15:0] q1final; logic q1ptr; logic [1:0] q1sel; logic [2:0] qren; logic consume_fb1, consume_fb0; logic [1:0] icaf_eff; localparam BRDATA_SIZE = pt.BTB_ENABLE ? 16+($clog2(pt.BTB_SIZE)*2*pt.BTB_FULLYA) : 4; localparam BRDATA_WIDTH = pt.BTB_ENABLE ? 8+($clog2(pt.BTB_SIZE)*pt.BTB_FULLYA) : 2; logic [BRDATA_SIZE-1:0] brdata_in, brdata2, brdata1, brdata0; logic [BRDATA_SIZE-1:0] brdata1eff, brdata0eff; logic [BRDATA_SIZE-1:0] brdata1final, brdata0final; localparam MHI = 1+(pt.BTB_ENABLE * (43+pt.BHT_GHR_SIZE)); localparam MSIZE = 2+(pt.BTB_ENABLE * (43+pt.BHT_GHR_SIZE)); logic [MHI:0] misc_data_in, misc2, misc1, misc0; logic [MHI:0] misc1eff, misc0eff; logic [pt.BTB_BTAG_SIZE-1:0] firstbrtag_hash, secondbrtag_hash; logic error_stall_in, error_stall; assign error_stall_in = (error_stall | ifu_async_error_start) & ~exu_flush_final; rvdff #(.WIDTH(7)) bundle1ff (.*, .clk(active_clk), .din ({wrptr_in[1:0],rdptr_in[1:0],q2off_in,q1off_in,q0off_in}), .dout({wrptr[1:0], rdptr[1:0], q2off, q1off, q0off}) ); rvdffie #(.WIDTH(7),.OVERRIDE(1)) bundle2ff (.*, .din ({error_stall_in,f2val_in[1:0],f1val_in[1:0],f0val_in[1:0]}), .dout({error_stall, f2val[1:0], f1val[1:0], f0val[1:0] }) ); if(pt.BTB_ENABLE==1) begin : genblock1 rvdffe #(BRDATA_SIZE) brdata2ff (.*, .clk(clk), .en(qwen[2]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata2[BRDATA_SIZE-1:0])); rvdffe #(BRDATA_SIZE) brdata1ff (.*, .clk(clk), .en(qwen[1]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata1[BRDATA_SIZE-1:0])); rvdffe #(BRDATA_SIZE) brdata0ff (.*, .clk(clk), .en(qwen[0]), .din(brdata_in[BRDATA_SIZE-1:0]), .dout(brdata0[BRDATA_SIZE-1:0])); rvdffe #(MSIZE) misc2ff (.*, .clk(clk), .en(qwen[2]), .din(misc_data_in[MHI:0]), .dout(misc2[MHI:0])); rvdffe #(MSIZE) misc1ff (.*, .clk(clk), .en(qwen[1]), .din(misc_data_in[MHI:0]), .dout(misc1[MHI:0])); rvdffe #(MSIZE) misc0ff (.*, .clk(clk), .en(qwen[0]), .din(misc_data_in[MHI:0]), .dout(misc0[MHI:0])); end else begin : genblock1 rvdffie #((MSIZE*3)+(BRDATA_SIZE*3)) miscff (.*, .din({qwen[2] ? {misc_data_in[MHI:0], brdata_in[BRDATA_SIZE-1:0]} : {misc2[MHI:0], brdata2[BRDATA_SIZE-1:0]}, qwen[1] ? {misc_data_in[MHI:0], brdata_in[BRDATA_SIZE-1:0]} : {misc1[MHI:0], brdata1[BRDATA_SIZE-1:0]}, qwen[0] ? {misc_data_in[MHI:0], brdata_in[BRDATA_SIZE-1:0]} : {misc0[MHI:0], brdata0[BRDATA_SIZE-1:0]}}), .dout({misc2[MHI:0], brdata2[BRDATA_SIZE-1:0], misc1[MHI:0], brdata1[BRDATA_SIZE-1:0], misc0[MHI:0], brdata0[BRDATA_SIZE-1:0]}) ); end logic [31:1] q2pc, q1pc, q0pc; rvdffe #(31) q2pcff (.*, .clk(clk), .en(qwen[2]), .din(ifu_fetch_pc[31:1]), .dout(q2pc[31:1])); rvdffe #(31) q1pcff (.*, .clk(clk), .en(qwen[1]), .din(ifu_fetch_pc[31:1]), .dout(q1pc[31:1])); rvdffe #(31) q0pcff (.*, .clk(clk), .en(qwen[0]), .din(ifu_fetch_pc[31:1]), .dout(q0pc[31:1])); rvdffe #(32) q2ff (.*, .clk(clk), .en(qwen[2]), .din(ifu_fetch_data_f[31:0]), .dout(q2[31:0])); rvdffe #(32) q1ff (.*, .clk(clk), .en(qwen[1]), .din(ifu_fetch_data_f[31:0]), .dout(q1[31:0])); rvdffe #(32) q0ff (.*, .clk(clk), .en(qwen[0]), .din(ifu_fetch_data_f[31:0]), .dout(q0[31:0])); // new queue control logic assign qren[2:0] = { rdptr[1:0] == 2'b10, rdptr[1:0] == 2'b01, rdptr[1:0] == 2'b00 }; assign qwen[2:0] = { (wrptr[1:0] == 2'b10) & ifvalid, (wrptr[1:0] == 2'b01) & ifvalid, (wrptr[1:0] == 2'b00) & ifvalid }; assign rdptr_in[1:0] = ({2{ qren[0] & ifu_fb_consume1 & ~exu_flush_final}} & 2'b01 ) | ({2{ qren[1] & ifu_fb_consume1 & ~exu_flush_final}} & 2'b10 ) | ({2{ qren[2] & ifu_fb_consume1 & ~exu_flush_final}} & 2'b00 ) | ({2{ qren[0] & ifu_fb_consume2 & ~exu_flush_final}} & 2'b10 ) | ({2{ qren[1] & ifu_fb_consume2 & ~exu_flush_final}} & 2'b00 ) | ({2{ qren[2] & ifu_fb_consume2 & ~exu_flush_final}} & 2'b01 ) | ({2{~ifu_fb_consume1 & ~ifu_fb_consume2 & ~exu_flush_final}} & rdptr[1:0]); assign wrptr_in[1:0] = ({2{ qwen[0] & ~exu_flush_final}} & 2'b01 ) | ({2{ qwen[1] & ~exu_flush_final}} & 2'b10 ) | ({2{ qwen[2] & ~exu_flush_final}} & 2'b00 ) | ({2{~ifvalid & ~exu_flush_final}} & wrptr[1:0]); assign q2off_in = ( ~qwen[2] & (rdptr[1:0]==2'd2) & (q2off | f0_shift_2B) ) | ( ~qwen[2] & (rdptr[1:0]==2'd1) & (q2off | f1_shift_2B) ) | ( ~qwen[2] & (rdptr[1:0]==2'd0) & q2off ); assign q1off_in = ( ~qwen[1] & (rdptr[1:0]==2'd1) & (q1off | f0_shift_2B) ) | ( ~qwen[1] & (rdptr[1:0]==2'd0) & (q1off | f1_shift_2B) ) | ( ~qwen[1] & (rdptr[1:0]==2'd2) & q1off ); assign q0off_in = ( ~qwen[0] & (rdptr[1:0]==2'd0) & (q0off | f0_shift_2B) ) | ( ~qwen[0] & (rdptr[1:0]==2'd2) & (q0off | f1_shift_2B) ) | ( ~qwen[0] & (rdptr[1:0]==2'd1) & q0off ); assign q0ptr = ( (rdptr[1:0]==2'b00) & q0off ) | ( (rdptr[1:0]==2'b01) & q1off ) | ( (rdptr[1:0]==2'b10) & q2off ); assign q1ptr = ( (rdptr[1:0]==2'b00) & q1off ) | ( (rdptr[1:0]==2'b01) & q2off ) | ( (rdptr[1:0]==2'b10) & q0off ); assign q0sel[1:0] = {q0ptr,~q0ptr}; assign q1sel[1:0] = {q1ptr,~q1ptr}; // end new queue control logic // misc data that is associated with each fetch buffer if(pt.BTB_ENABLE==1) assign misc_data_in[MHI:0] = { ic_access_fault_type_f[1:0], ifu_bp_btb_target_f[31:1], ifu_bp_poffset_f[11:0], ifu_bp_fghr_f[pt.BHT_GHR_SIZE-1:0] }; else assign misc_data_in[MHI:0] = { ic_access_fault_type_f[1:0] }; assign {misc1eff[MHI:0],misc0eff[MHI:0]} = (({MSIZE*2{qren[0]}} & {misc1[MHI:0],misc0[MHI:0]}) | ({MSIZE*2{qren[1]}} & {misc2[MHI:0],misc1[MHI:0]}) | ({MSIZE*2{qren[2]}} & {misc0[MHI:0],misc2[MHI:0]})); if(pt.BTB_ENABLE==1) begin assign { f1ictype[1:0], f1prett[31:1], f1poffset[11:0], f1fghr[pt.BHT_GHR_SIZE-1:0] } = misc1eff[MHI:0]; assign { f0ictype[1:0], f0prett[31:1], f0poffset[11:0], f0fghr[pt.BHT_GHR_SIZE-1:0] } = misc0eff[MHI:0]; if(pt.BTB_FULLYA) begin assign brdata_in[BRDATA_SIZE-1:0] = { ifu_bp_fa_index_f[1], iccm_rd_ecc_double_err[1],ic_access_fault_f[1],ifu_bp_hist1_f[1],ifu_bp_hist0_f[1],ifu_bp_pc4_f[1],ifu_bp_way_f[1],ifu_bp_valid_f[1],ifu_bp_ret_f[1], ifu_bp_fa_index_f[0], iccm_rd_ecc_double_err[0],ic_access_fault_f[0],ifu_bp_hist1_f[0],ifu_bp_hist0_f[0],ifu_bp_pc4_f[0],ifu_bp_way_f[0],ifu_bp_valid_f[0],ifu_bp_ret_f[0] }; assign {f0index[1],f0dbecc[1],f0icaf[1],f0hist1[1],f0hist0[1],f0pc4[1],f0way[1],f0brend[1],f0ret[1], f0index[0],f0dbecc[0],f0icaf[0],f0hist1[0],f0hist0[0],f0pc4[0],f0way[0],f0brend[0],f0ret[0]} = brdata0final[BRDATA_SIZE-1:0]; assign {f1index[1],f1dbecc[1],f1icaf[1],f1hist1[1],f1hist0[1],f1pc4[1],f1way[1],f1brend[1],f1ret[1], f1index[0],f1dbecc[0],f1icaf[0],f1hist1[0],f1hist0[0],f1pc4[0],f1way[0],f1brend[0],f1ret[0]} = brdata1final[BRDATA_SIZE-1:0]; end else begin assign brdata_in[BRDATA_SIZE-1:0] = { iccm_rd_ecc_double_err[1],ic_access_fault_f[1],ifu_bp_hist1_f[1],ifu_bp_hist0_f[1],ifu_bp_pc4_f[1],ifu_bp_way_f[1],ifu_bp_valid_f[1],ifu_bp_ret_f[1], iccm_rd_ecc_double_err[0],ic_access_fault_f[0],ifu_bp_hist1_f[0],ifu_bp_hist0_f[0],ifu_bp_pc4_f[0],ifu_bp_way_f[0],ifu_bp_valid_f[0],ifu_bp_ret_f[0] }; assign {f0dbecc[1],f0icaf[1],f0hist1[1],f0hist0[1],f0pc4[1],f0way[1],f0brend[1],f0ret[1], f0dbecc[0],f0icaf[0],f0hist1[0],f0hist0[0],f0pc4[0],f0way[0],f0brend[0],f0ret[0]} = brdata0final[BRDATA_SIZE-1:0]; assign {f1dbecc[1],f1icaf[1],f1hist1[1],f1hist0[1],f1pc4[1],f1way[1],f1brend[1],f1ret[1], f1dbecc[0],f1icaf[0],f1hist1[0],f1hist0[0],f1pc4[0],f1way[0],f1brend[0],f1ret[0]} = brdata1final[BRDATA_SIZE-1:0]; end assign {brdata1eff[BRDATA_SIZE-1:0],brdata0eff[BRDATA_SIZE-1:0]} = (({BRDATA_SIZE*2{qren[0]}} & {brdata1[BRDATA_SIZE-1:0],brdata0[BRDATA_SIZE-1:0]}) | ({BRDATA_SIZE*2{qren[1]}} & {brdata2[BRDATA_SIZE-1:0],brdata1[BRDATA_SIZE-1:0]}) | ({BRDATA_SIZE*2{qren[2]}} & {brdata0[BRDATA_SIZE-1:0],brdata2[BRDATA_SIZE-1:0]})); assign brdata0final[BRDATA_SIZE-1:0] = (({BRDATA_SIZE{q0sel[0]}} & { brdata0eff[2*BRDATA_WIDTH-1:0]}) | ({BRDATA_SIZE{q0sel[1]}} & {{BRDATA_WIDTH{1'b0}},brdata0eff[BRDATA_SIZE-1:BRDATA_WIDTH]})); assign brdata1final[BRDATA_SIZE-1:0] = (({BRDATA_SIZE{q1sel[0]}} & { brdata1eff[2*BRDATA_WIDTH-1:0]}) | ({BRDATA_SIZE{q1sel[1]}} & {{BRDATA_WIDTH{1'b0}},brdata1eff[BRDATA_SIZE-1:BRDATA_WIDTH]})); end // if (pt.BTB_ENABLE==1) else begin assign { f1ictype[1:0] } = misc1eff[MHI:0]; assign { f0ictype[1:0] } = misc0eff[MHI:0]; assign brdata_in[BRDATA_SIZE-1:0] = { iccm_rd_ecc_double_err[1],ic_access_fault_f[1], iccm_rd_ecc_double_err[0],ic_access_fault_f[0] }; assign {f0dbecc[1],f0icaf[1], f0dbecc[0],f0icaf[0]} = brdata0final[BRDATA_SIZE-1:0]; assign {f1dbecc[1],f1icaf[1], f1dbecc[0],f1icaf[0]} = brdata1final[BRDATA_SIZE-1:0]; assign {brdata1eff[BRDATA_SIZE-1:0],brdata0eff[BRDATA_SIZE-1:0]} = (({BRDATA_SIZE*2{qren[0]}} & {brdata1[BRDATA_SIZE-1:0],brdata0[BRDATA_SIZE-1:0]}) | ({BRDATA_SIZE*2{qren[1]}} & {brdata2[BRDATA_SIZE-1:0],brdata1[BRDATA_SIZE-1:0]}) | ({BRDATA_SIZE*2{qren[2]}} & {brdata0[BRDATA_SIZE-1:0],brdata2[BRDATA_SIZE-1:0]})); assign brdata0final[BRDATA_SIZE-1:0] = (({BRDATA_SIZE{q0sel[0]}} & { brdata0eff[2*BRDATA_WIDTH-1:0]}) | ({BRDATA_SIZE{q0sel[1]}} & {{BRDATA_WIDTH{1'b0}},brdata0eff[BRDATA_SIZE-1:BRDATA_WIDTH]})); assign brdata1final[BRDATA_SIZE-1:0] = (({BRDATA_SIZE{q1sel[0]}} & { brdata1eff[2*BRDATA_WIDTH-1:0]}) | ({BRDATA_SIZE{q1sel[1]}} & {{BRDATA_WIDTH{1'b0}},brdata1eff[BRDATA_SIZE-1:BRDATA_WIDTH]})); end // else: !if(pt.BTB_ENABLE==1) // possible states of { sf0_valid, sf1_valid, f2_valid } // // 000 if->f0 // 100 if->f1 // 101 illegal // 010 if->f1, f1->f0 // 110 if->f2 // 001 if->f1, f2->f0 // 011 if->f2, f2->f1, f1->f0 // 111 !if, no shift assign f2_valid = f2val[0]; assign sf1_valid = sf1val[0]; assign sf0_valid = sf0val[0]; // interface to fetch assign consume_fb0 = ~sf0val[0] & f0val[0]; assign consume_fb1 = ~sf1val[0] & f1val[0]; assign ifu_fb_consume1 = consume_fb0 & ~consume_fb1 & ~exu_flush_final; assign ifu_fb_consume2 = consume_fb0 & consume_fb1 & ~exu_flush_final; assign ifvalid = ifu_fetch_val[0]; assign shift_f1_f0 = ~sf0_valid & sf1_valid; assign shift_f2_f0 = ~sf0_valid & ~sf1_valid & f2_valid; assign shift_f2_f1 = ~sf0_valid & sf1_valid & f2_valid; assign fetch_to_f0 = ~sf0_valid & ~sf1_valid & ~f2_valid & ifvalid; assign fetch_to_f1 = (~sf0_valid & ~sf1_valid & f2_valid & ifvalid) | (~sf0_valid & sf1_valid & ~f2_valid & ifvalid) | ( sf0_valid & ~sf1_valid & ~f2_valid & ifvalid); assign fetch_to_f2 = (~sf0_valid & sf1_valid & f2_valid & ifvalid) | ( sf0_valid & sf1_valid & ~f2_valid & ifvalid); assign f2val_in[1:0] = ({2{ fetch_to_f2 & ~exu_flush_final}} & ifu_fetch_val[1:0]) | ({2{~fetch_to_f2 & ~shift_f2_f1 & ~shift_f2_f0 & ~exu_flush_final}} & f2val[1:0] ); assign sf1val[1:0] = ({2{ f1_shift_2B}} & {1'b0,f1val[1]}) | ({2{~f1_shift_2B}} & f1val[1:0] ); assign f1val_in[1:0] = ({2{ fetch_to_f1 & ~exu_flush_final}} & ifu_fetch_val[1:0]) | ({2{ shift_f2_f1 & ~exu_flush_final}} & f2val[1:0] ) | ({2{~fetch_to_f1 & ~shift_f2_f1 & ~shift_f1_f0 & ~exu_flush_final}} & sf1val[1:0] ); assign sf0val[1:0] = ({2{ shift_2B }} & {1'b0,f0val[1]}) | ({2{~shift_2B & ~shift_4B}} & f0val[1:0]); assign f0val_in[1:0] = ({2{fetch_to_f0 & ~exu_flush_final}} & ifu_fetch_val[1:0]) | ({2{ shift_f2_f0 & ~exu_flush_final}} & f2val[1:0] ) | ({2{ shift_f1_f0 & ~exu_flush_final}} & sf1val[1:0] ) | ({2{~fetch_to_f0 & ~shift_f2_f0 & ~shift_f1_f0 & ~exu_flush_final}} & sf0val[1:0] ); assign {q1eff[31:0],q0eff[31:0]} = (({64{qren[0]}} & {q1[31:0],q0[31:0]}) | ({64{qren[1]}} & {q2[31:0],q1[31:0]}) | ({64{qren[2]}} & {q0[31:0],q2[31:0]})); assign q0final[31:0] = ({32{q0sel[0]}} & { q0eff[31:0]}) | ({32{q0sel[1]}} & {16'b0,q0eff[31:16]}); assign q1final[15:0] = ({16{q1sel[0]}} & q1eff[15:0] ) | ({16{q1sel[1]}} & q1eff[31:16]); logic [31:1] q0pceff, q0pcfinal; logic [31:1] q1pceff; assign {q1pceff[31:1],q0pceff[31:1]} = (({62{qren[0]}} & {q1pc[31:1],q0pc[31:1]}) | ({62{qren[1]}} & {q2pc[31:1],q1pc[31:1]}) | ({62{qren[2]}} & {q0pc[31:1],q2pc[31:1]})); assign q0pcfinal[31:1] = ({31{q0sel[0]}} & ( q0pceff[31:1])) | ({31{q0sel[1]}} & ( q0pceff[31:1] + 31'd1)); assign aligndata[31:0] = ({32{ f0val[1] }} & {q0final[31:0]}) | ({32{~f0val[1] & f0val[0]}} & {q1final[15:0],q0final[15:0]}); assign alignval[1:0] = ({ 2{ f0val[1] }} & {2'b11}) | ({ 2{~f0val[1] & f0val[0]}} & {f1val[0],1'b1}); assign alignicaf[1:0] = ({ 2{ f0val[1] }} & f0icaf[1:0] ) | ({ 2{~f0val[1] & f0val[0]}} & {f1icaf[0],f0icaf[0]}); assign aligndbecc[1:0] = ({ 2{ f0val[1] }} & f0dbecc[1:0] ) | ({ 2{~f0val[1] & f0val[0]}} & {f1dbecc[0],f0dbecc[0]}); if (pt.BTB_ENABLE==1) begin // for branch prediction assign alignbrend[1:0] = ({ 2{ f0val[1] }} & f0brend[1:0] ) | ({ 2{~f0val[1] & f0val[0]}} & {f1brend[0],f0brend[0]}); assign alignpc4[1:0] = ({ 2{ f0val[1] }} & f0pc4[1:0] ) | ({ 2{~f0val[1] & f0val[0]}} & {f1pc4[0],f0pc4[0]}); if(pt.BTB_FULLYA) begin assign alignindex[0] = f0index[0]; assign alignindex[1] = f0val[1] ? f0index[1] : f1index[0]; end assign alignret[1:0] = ({ 2{ f0val[1] }} & f0ret[1:0] ) | ({ 2{~f0val[1] & f0val[0]}} & {f1ret[0],f0ret[0]}); assign alignway[1:0] = ({ 2{ f0val[1] }} & f0way[1:0] ) | ({ 2{~f0val[1] & f0val[0]}} & {f1way[0],f0way[0]}); assign alignhist1[1:0] = ({ 2{ f0val[1] }} & f0hist1[1:0] ) | ({ 2{~f0val[1] & f0val[0]}} & {f1hist1[0],f0hist1[0]}); assign alignhist0[1:0] = ({ 2{ f0val[1] }} & f0hist0[1:0] ) | ({ 2{~f0val[1] & f0val[0]}} & {f1hist0[0],f0hist0[0]}); assign secondpc[31:1] = ({31{ f0val[1] }} & (q0pceff[31:1] + 31'd1)) | // you need the base pc for 2nd one only (4B max, 2B for the 1st and 2B for the 2nd) ({31{~f0val[1] & f0val[0]}} & q1pceff[31:1] ); assign firstpc[31:1] = q0pcfinal[31:1]; end // if (pt.BTB_ENABLE==1) assign alignfromf1[1] = ~f0val[1] & f0val[0]; assign ifu_i0_pc[31:1] = q0pcfinal[31:1]; assign ifu_i0_pc4 = first4B; assign ifu_i0_cinst[15:0] = aligndata[15:0]; assign first4B = (aligndata[1:0] == 2'b11); assign first2B = ~first4B; assign ifu_i0_valid = (first4B & alignval[1]) | (first2B & alignval[0]); // inst access fault on any byte of inst results in access fault for the inst assign ifu_i0_icaf = (first4B & (|alignicaf[1:0])) | (first2B & alignicaf[0] ); assign ifu_i0_icaf_type[1:0] = (first4B & ~f0val[1] & f0val[0] & ~alignicaf[0] & ~aligndbecc[0]) ? f1ictype[1:0] : f0ictype[1:0]; assign icaf_eff[1:0] = alignicaf[1:0] | aligndbecc[1:0]; assign ifu_i0_icaf_second = first4B & ~icaf_eff[0] & icaf_eff[1]; assign ifu_i0_dbecc = (first4B & (|aligndbecc[1:0])) | (first2B & aligndbecc[0] ); assign ifirst[31:0] = aligndata[31:0]; assign ifu_i0_instr[31:0] = ({32{first4B & alignval[1]}} & ifirst[31:0]) | ({32{first2B & alignval[0]}} & uncompress0[31:0]); if(pt.BTB_ENABLE==1) begin : genblock2 // if you detect br does not start on instruction boundary el2_btb_addr_hash #(.pt(pt)) firsthash (.pc(firstpc [pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]), .hash(firstpc_hash [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO])); el2_btb_addr_hash #(.pt(pt)) secondhash(.pc(secondpc[pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]), .hash(secondpc_hash[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO])); if(pt.BTB_FULLYA) begin assign firstbrtag_hash = firstpc; assign secondbrtag_hash = secondpc; end else begin if(pt.BTB_BTAG_FOLD) begin : btbfold el2_btb_tag_hash_fold #(.pt(pt)) first_brhash (.pc(firstpc [pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]), .hash(firstbrtag_hash [pt.BTB_BTAG_SIZE-1:0])); el2_btb_tag_hash_fold #(.pt(pt)) second_brhash(.pc(secondpc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]), .hash(secondbrtag_hash[pt.BTB_BTAG_SIZE-1:0])); end else begin : btbfold el2_btb_tag_hash #(.pt(pt)) first_brhash (.pc(firstpc [pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]), .hash(firstbrtag_hash [pt.BTB_BTAG_SIZE-1:0])); el2_btb_tag_hash #(.pt(pt)) second_brhash(.pc(secondpc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]), .hash(secondbrtag_hash[pt.BTB_BTAG_SIZE-1:0])); end end // else: !if(pt.BTB_FULLYA) // start_indexing - you want pc to be based on where the end of branch is prediction // normal indexing pc based that's incorrect now for pc4 cases it's pc4 + 2 always_comb begin i0_brp = '0; i0_br_start_error = (first4B & alignval[1] & alignbrend[0]); i0_brp.valid = (first2B & alignbrend[0]) | (first4B & alignbrend[1]) | i0_br_start_error; i0_brp_pc4 = (first2B & alignpc4[0]) | (first4B & alignpc4[1]); i0_brp.ret = (first2B & alignret[0]) | (first4B & alignret[1]); i0_brp.way = (first2B | alignbrend[0]) ? alignway[0] : alignway[1]; i0_brp.hist[1] = (first2B & alignhist1[0]) | (first4B & alignhist1[1]); i0_brp.hist[0] = (first2B & alignhist0[0]) | (first4B & alignhist0[1]); i0_ends_f1 = first4B & alignfromf1[1]; i0_brp.toffset[11:0] = (i0_ends_f1) ? f1poffset[11:0] : f0poffset[11:0]; i0_brp.prett[31:1] = (i0_ends_f1) ? f1prett[31:1] : f0prett[31:1]; i0_brp.br_start_error = i0_br_start_error; i0_brp.bank = (first2B | alignbrend[0]) ? firstpc[1] : secondpc[1]; i0_brp.br_error = (i0_brp.valid & i0_brp_pc4 & first2B) | (i0_brp.valid & ~i0_brp_pc4 & first4B); if(pt.BTB_FULLYA) ifu_i0_fa_index = (first2B | alignbrend[0]) ? alignindex[0] : alignindex[1]; else ifu_i0_fa_index = '0; end assign ifu_i0_bp_index[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = (first2B | alignbrend[0]) ? firstpc_hash[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] : secondpc_hash[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]; assign ifu_i0_bp_fghr[pt.BHT_GHR_SIZE-1:0] = (i0_ends_f1) ? f1fghr[pt.BHT_GHR_SIZE-1:0] : f0fghr[pt.BHT_GHR_SIZE-1:0]; assign ifu_i0_bp_btag[pt.BTB_BTAG_SIZE-1:0] = (first2B | alignbrend[0]) ? firstbrtag_hash[pt.BTB_BTAG_SIZE-1:0] : secondbrtag_hash[pt.BTB_BTAG_SIZE-1:0]; end else begin assign i0_brp = '0; assign ifu_i0_bp_index = '0; assign ifu_i0_bp_fghr = '0; assign ifu_i0_bp_btag = '0; end // else: !if(pt.BTB_ENABLE==1) // decompress // quiet inputs for 4B inst el2_ifu_compress_ctl compress0 (.din((first2B) ? aligndata[15:0] : '0), .dout(uncompress0[31:0])); assign i0_shift = dec_i0_decode_d & ~error_stall; assign ifu_pmu_instr_aligned = i0_shift; // compute how many bytes are being shifted from f0 assign shift_2B = i0_shift & first2B; assign shift_4B = i0_shift & first4B; // exact equations for the queue logic assign f0_shift_2B = (shift_2B & f0val[0] ) | (shift_4B & f0val[0] & ~f0val[1]); // f0 valid states // 11 // 10 // 00 assign f1_shift_2B = f0val[0] & ~f0val[1] & shift_4B; endmodule ================================================ FILE: design/ifu/el2_ifu_bp_ctl.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** //******************************************************************************** // Function: Branch predictor // Comments: // // // Bank3 : Bank2 : Bank1 : Bank0 // FA C 8 4 0 //******************************************************************************** module el2_ifu_bp_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic ic_hit_f, // Icache hit, enables F address capture input logic [31:1] ifc_fetch_addr_f, // look up btb address input logic ifc_fetch_req_f, // F1 valid input el2_br_tlu_pkt_t dec_tlu_br0_r_pkt, // BP commit update packet, includes errors input logic [pt.BHT_GHR_SIZE-1:0] exu_i0_br_fghr_r, // fghr to bp input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_i0_br_index_r, // bp index input logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index, // Fully associative btb error index input logic dec_tlu_flush_lower_wb, // used to move EX4 RS to EX1 and F input logic dec_tlu_flush_leak_one_wb, // don't hit for leak one fetches input logic dec_tlu_bpred_disable, // disable all branch prediction input el2_predict_pkt_t exu_mp_pkt, // mispredict packet input logic [pt.BHT_GHR_SIZE-1:0] exu_mp_eghr, // execute ghr (for patching fghr) input logic [pt.BHT_GHR_SIZE-1:0] exu_mp_fghr, // Mispredict fghr input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_mp_index, // Mispredict index input logic [pt.BTB_BTAG_SIZE-1:0] exu_mp_btag, // Mispredict btag input logic exu_flush_final, // all flushes output logic ifu_bp_hit_taken_f, // btb hit, select target output logic [31:1] ifu_bp_btb_target_f, // predicted target PC output logic ifu_bp_inst_mask_f, // tell ic which valids to kill because of a taken branch, right justified output logic [pt.BHT_GHR_SIZE-1:0] ifu_bp_fghr_f, // fetch ghr output logic [1:0] ifu_bp_way_f, // way output logic [1:0] ifu_bp_ret_f, // predicted ret output logic [1:0] ifu_bp_hist1_f, // history counters for all 4 potential branches, bit 1, right justified output logic [1:0] ifu_bp_hist0_f, // history counters for all 4 potential branches, bit 0, right justified output logic [1:0] ifu_bp_pc4_f, // pc4 indication, right justified output logic [1:0] ifu_bp_valid_f, // branch valid, right justified output logic [11:0] ifu_bp_poffset_f, // predicted target output logic [1:0] [$clog2(pt.BTB_SIZE)-1:0] ifu_bp_fa_index_f, // predicted branch index (fully associative option) // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); localparam BTB_DWIDTH = pt.BTB_TOFFSET_SIZE+pt.BTB_BTAG_SIZE+5; localparam BTB_DWIDTH_TOP = int'(pt.BTB_TOFFSET_SIZE)+int'(pt.BTB_BTAG_SIZE)+4; localparam BTB_FA_INDEX = $clog2(pt.BTB_SIZE)-1; localparam FA_CMP_LOWER = $clog2(pt.ICACHE_LN_SZ); localparam FA_TAG_END_UPPER= 5+int'(pt.BTB_TOFFSET_SIZE)+int'(FA_CMP_LOWER)-1; // must cast to int or vcs build fails localparam FA_TAG_START_LOWER = 3+int'(pt.BTB_TOFFSET_SIZE)+int'(FA_CMP_LOWER); localparam FA_TAG_END_LOWER = 5+int'(pt.BTB_TOFFSET_SIZE); localparam TAG_START=BTB_DWIDTH-1; localparam PC4=4; localparam BOFF=3; localparam CALL=2; localparam RET=1; localparam BV=0; localparam LRU_SIZE=pt.BTB_ARRAY_DEPTH; localparam NUM_BHT_LOOP = (pt.BHT_ARRAY_DEPTH > 16 ) ? 16 : pt.BHT_ARRAY_DEPTH; localparam NUM_BHT_LOOP_INNER_HI = (pt.BHT_ARRAY_DEPTH > 16 ) ?pt.BHT_ADDR_LO+3 : pt.BHT_ADDR_HI; localparam NUM_BHT_LOOP_OUTER_LO = (pt.BHT_ARRAY_DEPTH > 16 ) ?pt.BHT_ADDR_LO+4 : pt.BHT_ADDR_LO; localparam BHT_NO_ADDR_MATCH = ( pt.BHT_ARRAY_DEPTH <= 16 ); logic exu_mp_valid_write; logic exu_mp_ataken; logic exu_mp_valid; // conditional branch mispredict logic exu_mp_boffset; // branch offsett logic exu_mp_pc4; // branch is a 4B inst logic exu_mp_call; // branch is a call inst logic exu_mp_ret; // branch is a ret inst logic exu_mp_ja; // branch is a jump always logic [1:0] exu_mp_hist; // new history logic [11:0] exu_mp_tgt; // target offset logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] exu_mp_addr; // BTB/BHT address logic dec_tlu_br0_v_wb; // WB stage history update logic [1:0] dec_tlu_br0_hist_wb; // new history logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] dec_tlu_br0_addr_wb; // addr logic dec_tlu_br0_error_wb; // error; invalidate bank logic dec_tlu_br0_start_error_wb; // error; invalidate all 4 banks in fg logic [pt.BHT_GHR_SIZE-1:0] exu_i0_br_fghr_wb; logic use_mp_way, use_mp_way_p1; logic [pt.RET_STACK_SIZE-1:0][31:0] rets_out, rets_in; logic [pt.RET_STACK_SIZE-1:0] rsenable; logic [11:0] btb_rd_tgt_f; logic btb_rd_pc4_f, btb_rd_call_f, btb_rd_ret_f; logic [1:1] bp_total_branch_offset_f; logic [31:1] bp_btb_target_adder_f; logic [31:1] bp_rs_call_target_f; logic rs_push, rs_pop, rs_hold; logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] btb_rd_addr_p1_f, btb_wr_addr, btb_rd_addr_f; logic [pt.BTB_BTAG_SIZE-1:0] btb_wr_tag, fetch_rd_tag_f, fetch_rd_tag_p1_f; logic [BTB_DWIDTH-1:0] btb_wr_data; logic btb_wr_en_way0, btb_wr_en_way1; logic dec_tlu_error_wb, btb_valid, dec_tlu_br0_middle_wb; logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] btb_error_addr_wb; logic branch_error_collision_f, fetch_mp_collision_f, branch_error_collision_p1_f, fetch_mp_collision_p1_f; logic branch_error_bank_conflict_f; logic [pt.BHT_GHR_SIZE-1:0] merged_ghr, fghr_ns, fghr; logic [1:0] num_valids; logic [LRU_SIZE-1:0] btb_lru_b0_f, btb_lru_b0_hold, btb_lru_b0_ns, fetch_wrindex_dec, fetch_wrindex_p1_dec, fetch_wrlru_b0, fetch_wrlru_p1_b0, mp_wrindex_dec, mp_wrlru_b0; logic btb_lru_rd_f, btb_lru_rd_p1_f, lru_update_valid_f; logic tag_match_way0_f, tag_match_way1_f; logic [1:0] way_raw, bht_dir_f, btb_sel_f, wayhit_f, vwayhit_f, wayhit_p1_f; logic [1:0] bht_valid_f, bht_force_taken_f; logic leak_one_f, leak_one_f_d1; logic [LRU_SIZE-1:0][BTB_DWIDTH-1:0] btb_bank0_rd_data_way0_out ; logic [LRU_SIZE-1:0][BTB_DWIDTH-1:0] btb_bank0_rd_data_way1_out ; logic [BTB_DWIDTH-1:0] btb_bank0_rd_data_way0_f ; logic [BTB_DWIDTH-1:0] btb_bank0_rd_data_way1_f ; logic [BTB_DWIDTH-1:0] btb_bank0_rd_data_way0_p1_f ; logic [BTB_DWIDTH-1:0] btb_bank0_rd_data_way1_p1_f ; logic [BTB_DWIDTH-1:0] btb_vbank0_rd_data_f, btb_vbank1_rd_data_f; logic final_h; logic btb_fg_crossing_f; logic middle_of_bank; logic [1:0] bht_vbank0_rd_data_f, bht_vbank1_rd_data_f; logic branch_error_bank_conflict_p1_f; logic tag_match_way0_p1_f, tag_match_way1_p1_f; logic [1:0] btb_vlru_rd_f, fetch_start_f, tag_match_vway1_expanded_f, tag_match_way0_expanded_p1_f, tag_match_way1_expanded_p1_f; logic [31:2] fetch_addr_p1_f; logic exu_mp_way, exu_mp_way_f, dec_tlu_br0_way_wb, dec_tlu_way_wb; logic [BTB_DWIDTH-1:0] btb_bank0e_rd_data_f, btb_bank0e_rd_data_p1_f; logic [BTB_DWIDTH-1:0] btb_bank0o_rd_data_f; logic [1:0] tag_match_way0_expanded_f, tag_match_way1_expanded_f; logic [1:0] bht_bank0_rd_data_f; logic [1:0] bht_bank1_rd_data_f; logic [1:0] bht_bank0_rd_data_p1_f; genvar j, i; assign exu_mp_valid = exu_mp_pkt.misp & ~leak_one_f; // conditional branch mispredict assign exu_mp_boffset = exu_mp_pkt.boffset; // branch offset assign exu_mp_pc4 = exu_mp_pkt.pc4; // branch is a 4B inst assign exu_mp_call = exu_mp_pkt.pcall; // branch is a call inst assign exu_mp_ret = exu_mp_pkt.pret; // branch is a ret inst assign exu_mp_ja = exu_mp_pkt.pja; // branch is a jump always assign exu_mp_way = exu_mp_pkt.way; // repl way assign exu_mp_hist[1:0] = exu_mp_pkt.hist[1:0]; // new history assign exu_mp_tgt[11:0] = exu_mp_pkt.toffset[11:0] ; // target offset assign exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = exu_mp_index[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ; // BTB/BHT address assign exu_mp_ataken = exu_mp_pkt.ataken; assign dec_tlu_br0_v_wb = dec_tlu_br0_r_pkt.valid; assign dec_tlu_br0_hist_wb[1:0] = dec_tlu_br0_r_pkt.hist[1:0]; assign dec_tlu_br0_addr_wb[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = exu_i0_br_index_r[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]; assign dec_tlu_br0_error_wb = dec_tlu_br0_r_pkt.br_error; assign dec_tlu_br0_middle_wb = dec_tlu_br0_r_pkt.middle; assign dec_tlu_br0_way_wb = dec_tlu_br0_r_pkt.way; assign dec_tlu_br0_start_error_wb = dec_tlu_br0_r_pkt.br_start_error; assign exu_i0_br_fghr_wb[pt.BHT_GHR_SIZE-1:0] = exu_i0_br_fghr_r[pt.BHT_GHR_SIZE-1:0]; // ---------------------------------------------------------------------- // READ // ---------------------------------------------------------------------- // hash the incoming fetch PC, first guess at hashing algorithm el2_btb_addr_hash #(.pt(pt)) f1hash(.pc(ifc_fetch_addr_f[pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]), .hash(btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO])); assign fetch_addr_p1_f[31:2] = ifc_fetch_addr_f[31:2] + 30'b1; el2_btb_addr_hash #(.pt(pt)) f1hash_p1(.pc(fetch_addr_p1_f[pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO]), .hash(btb_rd_addr_p1_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO])); assign btb_sel_f[1] = ~bht_dir_f[0]; assign btb_sel_f[0] = bht_dir_f[0]; assign fetch_start_f[1:0] = {ifc_fetch_addr_f[1], ~ifc_fetch_addr_f[1]}; // Errors colliding with fetches must kill the btb/bht hit. assign branch_error_collision_f = dec_tlu_error_wb & (btb_error_addr_wb[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]); assign branch_error_collision_p1_f = dec_tlu_error_wb & (btb_error_addr_wb[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == btb_rd_addr_p1_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]); assign branch_error_bank_conflict_f = branch_error_collision_f & dec_tlu_error_wb; assign branch_error_bank_conflict_p1_f = branch_error_collision_p1_f & dec_tlu_error_wb; // set on leak one, hold until next flush without leak one assign leak_one_f = (dec_tlu_flush_leak_one_wb & dec_tlu_flush_lower_wb) | (leak_one_f_d1 & ~dec_tlu_flush_lower_wb); logic exu_flush_final_d1; if(!pt.BTB_FULLYA) begin : genblock1 assign fetch_mp_collision_f = ( (exu_mp_btag[pt.BTB_BTAG_SIZE-1:0] == fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]) & exu_mp_valid & ifc_fetch_req_f & (exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]) ); assign fetch_mp_collision_p1_f = ( (exu_mp_btag[pt.BTB_BTAG_SIZE-1:0] == fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]) & exu_mp_valid & ifc_fetch_req_f & (exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] == btb_rd_addr_p1_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]) ); // 2 -way SA, figure out the way hit and mux accordingly assign tag_match_way0_f = btb_bank0_rd_data_way0_f[BV] & (btb_bank0_rd_data_way0_f[TAG_START:17] == fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]) & ~(dec_tlu_way_wb & branch_error_bank_conflict_f) & ifc_fetch_req_f & ~leak_one_f; assign tag_match_way1_f = btb_bank0_rd_data_way1_f[BV] & (btb_bank0_rd_data_way1_f[TAG_START:17] == fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]) & ~(dec_tlu_way_wb & branch_error_bank_conflict_f) & ifc_fetch_req_f & ~leak_one_f; assign tag_match_way0_p1_f = btb_bank0_rd_data_way0_p1_f[BV] & (btb_bank0_rd_data_way0_p1_f[TAG_START:17] == fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]) & ~(dec_tlu_way_wb & branch_error_bank_conflict_p1_f) & ifc_fetch_req_f & ~leak_one_f; assign tag_match_way1_p1_f = btb_bank0_rd_data_way1_p1_f[BV] & (btb_bank0_rd_data_way1_p1_f[TAG_START:17] == fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]) & ~(dec_tlu_way_wb & branch_error_bank_conflict_p1_f) & ifc_fetch_req_f & ~leak_one_f; // Both ways could hit, use the offset bit to reorder assign tag_match_way0_expanded_f[1:0] = {tag_match_way0_f & (btb_bank0_rd_data_way0_f[BOFF] ^ btb_bank0_rd_data_way0_f[PC4]), tag_match_way0_f & ~(btb_bank0_rd_data_way0_f[BOFF] ^ btb_bank0_rd_data_way0_f[PC4])}; assign tag_match_way1_expanded_f[1:0] = {tag_match_way1_f & (btb_bank0_rd_data_way1_f[BOFF] ^ btb_bank0_rd_data_way1_f[PC4]), tag_match_way1_f & ~(btb_bank0_rd_data_way1_f[BOFF] ^ btb_bank0_rd_data_way1_f[PC4])}; assign tag_match_way0_expanded_p1_f[1:0] = {tag_match_way0_p1_f & (btb_bank0_rd_data_way0_p1_f[BOFF] ^ btb_bank0_rd_data_way0_p1_f[PC4]), tag_match_way0_p1_f & ~(btb_bank0_rd_data_way0_p1_f[BOFF] ^ btb_bank0_rd_data_way0_p1_f[PC4])}; assign tag_match_way1_expanded_p1_f[1:0] = {tag_match_way1_p1_f & (btb_bank0_rd_data_way1_p1_f[BOFF] ^ btb_bank0_rd_data_way1_p1_f[PC4]), tag_match_way1_p1_f & ~(btb_bank0_rd_data_way1_p1_f[BOFF] ^ btb_bank0_rd_data_way1_p1_f[PC4])}; assign wayhit_f[1:0] = tag_match_way0_expanded_f[1:0] | tag_match_way1_expanded_f[1:0]; assign wayhit_p1_f[1:0] = tag_match_way0_expanded_p1_f[1:0] | tag_match_way1_expanded_p1_f[1:0]; assign btb_bank0o_rd_data_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_f[1]}} & btb_bank0_rd_data_way0_f[BTB_DWIDTH-1:0]) | ({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_f[1]}} & btb_bank0_rd_data_way1_f[BTB_DWIDTH-1:0]) ); assign btb_bank0e_rd_data_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_f[0]}} & btb_bank0_rd_data_way0_f[BTB_DWIDTH-1:0]) | ({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_f[0]}} & btb_bank0_rd_data_way1_f[BTB_DWIDTH-1:0]) ); assign btb_bank0e_rd_data_p1_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{tag_match_way0_expanded_p1_f[0]}} & btb_bank0_rd_data_way0_p1_f[BTB_DWIDTH-1:0]) | ({17+pt.BTB_BTAG_SIZE{tag_match_way1_expanded_p1_f[0]}} & btb_bank0_rd_data_way1_p1_f[BTB_DWIDTH-1:0]) ); // virtual bank order assign btb_vbank0_rd_data_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{fetch_start_f[0]}} & btb_bank0e_rd_data_f[BTB_DWIDTH-1:0]) | ({17+pt.BTB_BTAG_SIZE{fetch_start_f[1]}} & btb_bank0o_rd_data_f[BTB_DWIDTH-1:0]) ); assign btb_vbank1_rd_data_f[BTB_DWIDTH-1:0] = ( ({17+pt.BTB_BTAG_SIZE{fetch_start_f[0]}} & btb_bank0o_rd_data_f[BTB_DWIDTH-1:0]) | ({17+pt.BTB_BTAG_SIZE{fetch_start_f[1]}} & btb_bank0e_rd_data_p1_f[BTB_DWIDTH-1:0]) ); assign way_raw[1:0] = tag_match_vway1_expanded_f[1:0] | (~vwayhit_f[1:0] & btb_vlru_rd_f[1:0]); // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // update lru // mp // create a onehot lru write vector assign mp_wrindex_dec[LRU_SIZE-1:0] = {{LRU_SIZE-1{1'b0}},1'b1} << exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]; // fetch assign fetch_wrindex_dec[LRU_SIZE-1:0] = {{LRU_SIZE-1{1'b0}},1'b1} << btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]; assign fetch_wrindex_p1_dec[LRU_SIZE-1:0] = {{LRU_SIZE-1{1'b0}},1'b1} << btb_rd_addr_p1_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]; assign mp_wrlru_b0[LRU_SIZE-1:0] = mp_wrindex_dec[LRU_SIZE-1:0] & {LRU_SIZE{exu_mp_valid}}; assign btb_lru_b0_hold[LRU_SIZE-1:0] = ~mp_wrlru_b0[LRU_SIZE-1:0] & ~fetch_wrlru_b0[LRU_SIZE-1:0]; // Forward the mp lru information to the fetch, avoids multiple way hits later assign use_mp_way = fetch_mp_collision_f; assign use_mp_way_p1 = fetch_mp_collision_p1_f; assign lru_update_valid_f = (vwayhit_f[0] | vwayhit_f[1]) & ifc_fetch_req_f & ~leak_one_f; assign fetch_wrlru_b0[LRU_SIZE-1:0] = fetch_wrindex_dec[LRU_SIZE-1:0] & {LRU_SIZE{lru_update_valid_f}}; assign fetch_wrlru_p1_b0[LRU_SIZE-1:0] = fetch_wrindex_p1_dec[LRU_SIZE-1:0] & {LRU_SIZE{lru_update_valid_f}}; assign btb_lru_b0_ns[LRU_SIZE-1:0] = ( (btb_lru_b0_hold[LRU_SIZE-1:0] & btb_lru_b0_f[LRU_SIZE-1:0]) | (mp_wrlru_b0[LRU_SIZE-1:0] & {LRU_SIZE{~exu_mp_way}}) | (fetch_wrlru_b0[LRU_SIZE-1:0] & {LRU_SIZE{tag_match_way0_f}}) | (fetch_wrlru_p1_b0[LRU_SIZE-1:0] & {LRU_SIZE{tag_match_way0_p1_f}}) ); assign btb_lru_rd_f = use_mp_way ? exu_mp_way_f : |(fetch_wrindex_dec[LRU_SIZE-1:0] & btb_lru_b0_f[LRU_SIZE-1:0]); assign btb_lru_rd_p1_f = use_mp_way_p1 ? exu_mp_way_f : |(fetch_wrindex_p1_dec[LRU_SIZE-1:0] & btb_lru_b0_f[LRU_SIZE-1:0]); // rotated assign btb_vlru_rd_f[1:0] = ( ({2{fetch_start_f[0]}} & {btb_lru_rd_f, btb_lru_rd_f}) | ({2{fetch_start_f[1]}} & {btb_lru_rd_p1_f, btb_lru_rd_f})); assign tag_match_vway1_expanded_f[1:0] = ( ({2{fetch_start_f[0]}} & {tag_match_way1_expanded_f[1:0]}) | ({2{fetch_start_f[1]}} & {tag_match_way1_expanded_p1_f[0], tag_match_way1_expanded_f[1]}) ); rvdffe #(LRU_SIZE) btb_lru_ff (.*, .en(ifc_fetch_req_f | exu_mp_valid), .din(btb_lru_b0_ns[(LRU_SIZE)-1:0]), .dout(btb_lru_b0_f[(LRU_SIZE)-1:0])); end // if (!pt.BTB_FULLYA) // Detect end of cache line and mask as needed logic eoc_near; logic eoc_mask; assign eoc_near = &ifc_fetch_addr_f[pt.ICACHE_BEAT_ADDR_HI:3]; assign eoc_mask = ~eoc_near| (|(~ifc_fetch_addr_f[2:1])); // -------------------------------------------------------------------------------- // -------------------------------------------------------------------------------- // mux out critical hit bank for pc computation // This is only useful for the first taken branch in the fetch group logic [16:1] btb_sel_data_f; assign btb_rd_tgt_f[11:0] = btb_sel_data_f[16:5]; assign btb_rd_pc4_f = btb_sel_data_f[4]; assign btb_rd_call_f = btb_sel_data_f[2]; assign btb_rd_ret_f = btb_sel_data_f[1]; assign btb_sel_data_f[16:1] = ( ({16{btb_sel_f[1]}} & btb_vbank1_rd_data_f[16:1]) | ({16{btb_sel_f[0]}} & btb_vbank0_rd_data_f[16:1]) ); logic [1:0] hist0_raw, hist1_raw, pc4_raw, pret_raw; // a valid taken target needs to kill the next fetch as we compute the target address assign ifu_bp_hit_taken_f = |(vwayhit_f[1:0] & hist1_raw[1:0]) & ifc_fetch_req_f & ~leak_one_f_d1 & ~dec_tlu_bpred_disable; // Don't put calls/rets/ja in the predictor, force the bht taken instead assign bht_force_taken_f[1:0] = {(btb_vbank1_rd_data_f[CALL] | btb_vbank1_rd_data_f[RET]), (btb_vbank0_rd_data_f[CALL] | btb_vbank0_rd_data_f[RET])}; // taken and valid, otherwise, branch errors must clear the bht assign bht_valid_f[1:0] = vwayhit_f[1:0]; assign bht_vbank0_rd_data_f[1:0] = ( ({2{fetch_start_f[0]}} & bht_bank0_rd_data_f[1:0]) | ({2{fetch_start_f[1]}} & bht_bank1_rd_data_f[1:0]) ); assign bht_vbank1_rd_data_f[1:0] = ( ({2{fetch_start_f[0]}} & bht_bank1_rd_data_f[1:0]) | ({2{fetch_start_f[1]}} & bht_bank0_rd_data_p1_f[1:0]) ); assign bht_dir_f[1:0] = {(bht_force_taken_f[1] | bht_vbank1_rd_data_f[1]) & bht_valid_f[1], (bht_force_taken_f[0] | bht_vbank0_rd_data_f[1]) & bht_valid_f[0]}; assign ifu_bp_inst_mask_f = (ifu_bp_hit_taken_f & btb_sel_f[1]) | ~ifu_bp_hit_taken_f; // Branch prediction info is sent with the 2byte lane associated with the end of the branch. // Cases // BANK1 BANK0 // ------------------------------- // | : | : | // ------------------------------- // <------------> : PC4 branch, offset, should be in B1 (indicated on [2]) // <------------> : PC4 branch, no offset, indicate PC4, VALID, HIST on [1] // <------------> : PC4 branch, offset, indicate PC4, VALID, HIST on [0] // <------> : PC2 branch, offset, indicate VALID, HIST on [1] // <------> : PC2 branch, no offset, indicate VALID, HIST on [0] // assign hist1_raw[1:0] = bht_force_taken_f[1:0] | {bht_vbank1_rd_data_f[1], bht_vbank0_rd_data_f[1]}; assign hist0_raw[1:0] = {bht_vbank1_rd_data_f[0], bht_vbank0_rd_data_f[0]}; assign pc4_raw[1:0] = {vwayhit_f[1] & btb_vbank1_rd_data_f[PC4], vwayhit_f[0] & btb_vbank0_rd_data_f[PC4]}; assign pret_raw[1:0] = {vwayhit_f[1] & ~btb_vbank1_rd_data_f[CALL] & btb_vbank1_rd_data_f[RET], vwayhit_f[0] & ~btb_vbank0_rd_data_f[CALL] & btb_vbank0_rd_data_f[RET]}; // GHR // count the valids with masking based on first taken assign num_valids[1:0] = countones(bht_valid_f[1:0]); // Note that the following property holds // P: prior ghr, H: history bit of last valid branch in line (could be 1 or 0) // Num valid branches What new GHR must be // 2 0H // 1 PH // 0 PP assign final_h = |(btb_sel_f[1:0] & bht_dir_f[1:0]); assign merged_ghr[pt.BHT_GHR_SIZE-1:0] = ( ({pt.BHT_GHR_SIZE{num_valids[1:0] == 2'h2}} & {fghr[pt.BHT_GHR_SIZE-3:0], 1'b0, final_h}) | // 0H ({pt.BHT_GHR_SIZE{num_valids[1:0] == 2'h1}} & {fghr[pt.BHT_GHR_SIZE-2:0], final_h}) | // PH ({pt.BHT_GHR_SIZE{num_valids[1:0] == 2'h0}} & {fghr[pt.BHT_GHR_SIZE-1:0]}) ); // PP logic [pt.BHT_GHR_SIZE-1:0] exu_flush_ghr; assign exu_flush_ghr[pt.BHT_GHR_SIZE-1:0] = exu_mp_fghr[pt.BHT_GHR_SIZE-1:0]; assign fghr_ns[pt.BHT_GHR_SIZE-1:0] = ( ({pt.BHT_GHR_SIZE{exu_flush_final_d1}} & exu_flush_ghr[pt.BHT_GHR_SIZE-1:0]) | ({pt.BHT_GHR_SIZE{~exu_flush_final_d1 & ifc_fetch_req_f & ic_hit_f & ~leak_one_f_d1}} & merged_ghr[pt.BHT_GHR_SIZE-1:0]) | ({pt.BHT_GHR_SIZE{~exu_flush_final_d1 & ~(ifc_fetch_req_f & ic_hit_f & ~leak_one_f_d1)}} & fghr[pt.BHT_GHR_SIZE-1:0])); rvdffie #(.WIDTH(pt.BHT_GHR_SIZE+3),.OVERRIDE(1)) fetchghr (.*, .din ({exu_flush_final, exu_mp_way, leak_one_f, fghr_ns[pt.BHT_GHR_SIZE-1:0]}), .dout({exu_flush_final_d1, exu_mp_way_f, leak_one_f_d1, fghr[pt.BHT_GHR_SIZE-1:0]})); assign ifu_bp_fghr_f[pt.BHT_GHR_SIZE-1:0] = fghr[pt.BHT_GHR_SIZE-1:0]; assign ifu_bp_way_f[1:0] = way_raw[1:0]; assign ifu_bp_hist1_f[1:0] = hist1_raw[1:0]; assign ifu_bp_hist0_f[1:0] = hist0_raw[1:0]; assign ifu_bp_pc4_f[1:0] = pc4_raw[1:0]; assign ifu_bp_valid_f[1:0] = vwayhit_f[1:0] & ~{2{dec_tlu_bpred_disable}}; assign ifu_bp_ret_f[1:0] = pret_raw[1:0]; // compute target // Form the fetch group offset based on the btb hit location and the location of the branch within the 4 byte chunk // .i 5 // .o 3 // .ilb bht_dir_f[1] bht_dir_f[0] fetch_start_f[1] fetch_start_f[0] btb_rd_pc4_f // .ob bloc_f[1] bloc_f[0] use_fa_plus // .type fr // // // ## rotdir[1:0] fs pc4 off fapl // -1 01 - 01 0 // 10 01 - 10 0 // // -1 10 - 10 0 // 10 10 0 01 1 // 10 10 1 01 0 logic [1:0] bloc_f; logic use_fa_plus; assign bloc_f[1] = (bht_dir_f[0] & ~fetch_start_f[0]) | (~bht_dir_f[0] & fetch_start_f[0]); assign bloc_f[0] = (bht_dir_f[0] & fetch_start_f[0]) | (~bht_dir_f[0] & ~fetch_start_f[0]); assign use_fa_plus = (~bht_dir_f[0] & ~fetch_start_f[0] & ~btb_rd_pc4_f); assign btb_fg_crossing_f = fetch_start_f[0] & btb_sel_f[0] & btb_rd_pc4_f; assign bp_total_branch_offset_f = bloc_f[1] ^ btb_rd_pc4_f; logic [31:2] adder_pc_in_f, ifc_fetch_adder_prior; rvdfflie #(.WIDTH(30), .LEFT(19)) faddrf_ff (.*, .en(ifc_fetch_req_f & ~ifu_bp_hit_taken_f & ic_hit_f), .din(ifc_fetch_addr_f[31:2]), .dout(ifc_fetch_adder_prior[31:2])); assign ifu_bp_poffset_f[11:0] = btb_rd_tgt_f[11:0]; assign adder_pc_in_f[31:2] = ( ({30{ use_fa_plus}} & fetch_addr_p1_f[31:2]) | ({30{ btb_fg_crossing_f}} & ifc_fetch_adder_prior[31:2]) | ({30{~btb_fg_crossing_f & ~use_fa_plus}} & ifc_fetch_addr_f[31:2])); rvbradder predtgt_addr (.pc({adder_pc_in_f[31:2], bp_total_branch_offset_f}), .offset(btb_rd_tgt_f[11:0]), .dout(bp_btb_target_adder_f[31:1]) ); // mux in the return stack address here for a predicted return assuming the RS is valid, quite if no prediction assign ifu_bp_btb_target_f[31:1] = (({31{btb_rd_ret_f & ~btb_rd_call_f & rets_out[0][0] & ifu_bp_hit_taken_f}} & rets_out[0][31:1]) | ({31{~(btb_rd_ret_f & ~btb_rd_call_f & rets_out[0][0]) & ifu_bp_hit_taken_f}} & bp_btb_target_adder_f[31:1]) ); // ---------------------------------------------------------------------- // Return Stack // ---------------------------------------------------------------------- rvbradder rs_addr (.pc({adder_pc_in_f[31:2], bp_total_branch_offset_f}), .offset({11'b0, ~btb_rd_pc4_f}), .dout(bp_rs_call_target_f[31:1]) ); assign rs_push = (btb_rd_call_f & ~btb_rd_ret_f & ifu_bp_hit_taken_f); assign rs_pop = (btb_rd_ret_f & ~btb_rd_call_f & ifu_bp_hit_taken_f); assign rs_hold = ~rs_push & ~rs_pop; // Fetch based (bit 0 is a valid) assign rets_in[0][31:0] = ( ({32{rs_push}} & {bp_rs_call_target_f[31:1], 1'b1}) | // target[31:1], valid ({32{rs_pop}} & rets_out[1][31:0]) ); assign rsenable[0] = ~rs_hold; for (i=0; i0) begin assign rets_in[i][31:0] = ( ({32{rs_push}} & rets_out[i-1][31:0]) | ({32{rs_pop}} & rets_out[i+1][31:0]) ); assign rsenable[i] = rs_push | rs_pop; end rvdffe #(32) rets_ff (.*, .en(rsenable[i]), .din(rets_in[i][31:0]), .dout(rets_out[i][31:0])); end : retstack // ---------------------------------------------------------------------- // WRITE // ---------------------------------------------------------------------- assign dec_tlu_error_wb = dec_tlu_br0_start_error_wb | dec_tlu_br0_error_wb; assign btb_error_addr_wb[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = dec_tlu_br0_addr_wb[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]; assign dec_tlu_way_wb = dec_tlu_br0_way_wb; assign btb_valid = exu_mp_valid & ~dec_tlu_error_wb; assign btb_wr_tag[pt.BTB_BTAG_SIZE-1:0] = exu_mp_btag[pt.BTB_BTAG_SIZE-1:0]; if(!pt.BTB_FULLYA) begin if(pt.BTB_BTAG_FOLD) begin : btbfold el2_btb_tag_hash_fold #(.pt(pt)) rdtagf (.hash(fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]), .pc({ifc_fetch_addr_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]})); el2_btb_tag_hash_fold #(.pt(pt)) rdtagp1f(.hash(fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]), .pc({fetch_addr_p1_f[ pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]})); end else begin : btbfold el2_btb_tag_hash #(.pt(pt)) rdtagf(.hash(fetch_rd_tag_f[pt.BTB_BTAG_SIZE-1:0]), .pc({ifc_fetch_addr_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]})); el2_btb_tag_hash #(.pt(pt)) rdtagp1f(.hash(fetch_rd_tag_p1_f[pt.BTB_BTAG_SIZE-1:0]), .pc({fetch_addr_p1_f[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1]})); end assign btb_wr_en_way0 = ( ({{~exu_mp_way & exu_mp_valid_write & ~dec_tlu_error_wb}}) | ({{~dec_tlu_way_wb & dec_tlu_error_wb}})); assign btb_wr_en_way1 = ( ({{exu_mp_way & exu_mp_valid_write & ~dec_tlu_error_wb}}) | ({{dec_tlu_way_wb & dec_tlu_error_wb}})); assign btb_wr_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = dec_tlu_error_wb ? btb_error_addr_wb[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] : exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]; assign vwayhit_f[1:0] = ( ({2{fetch_start_f[0]}} & {wayhit_f[1:0]}) | ({2{fetch_start_f[1]}} & {wayhit_p1_f[0], wayhit_f[1]})) & {eoc_mask, 1'b1}; end // if (!pt.BTB_FULLYA) assign btb_wr_data[BTB_DWIDTH-1:0] = {btb_wr_tag[pt.BTB_BTAG_SIZE-1:0], exu_mp_tgt[pt.BTB_TOFFSET_SIZE-1:0], exu_mp_pc4, exu_mp_boffset, exu_mp_call | exu_mp_ja, exu_mp_ret | exu_mp_ja, btb_valid} ; assign exu_mp_valid_write = exu_mp_valid & exu_mp_ataken & ~exu_mp_pkt.valid; logic [1:0] bht_wr_data0, bht_wr_data2; logic [1:0] bht_wr_en0, bht_wr_en2; assign middle_of_bank = exu_mp_pc4 ^ exu_mp_boffset; assign bht_wr_en0[1:0] = {2{exu_mp_valid & ~exu_mp_call & ~exu_mp_ret & ~exu_mp_ja}} & {middle_of_bank, ~middle_of_bank}; assign bht_wr_en2[1:0] = {2{dec_tlu_br0_v_wb}} & {dec_tlu_br0_middle_wb, ~dec_tlu_br0_middle_wb} ; // Experiments show this is the best priority scheme for same bank/index writes at the same time. assign bht_wr_data0[1:0] = exu_mp_hist[1:0]; // lowest priority assign bht_wr_data2[1:0] = dec_tlu_br0_hist_wb[1:0]; // highest priority logic [pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] bht_rd_addr_f, bht_rd_addr_p1_f, bht_wr_addr0, bht_wr_addr2; logic [pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] mp_hashed, br0_hashed_wb, bht_rd_addr_hashed_f, bht_rd_addr_hashed_p1_f; el2_btb_ghr_hash #(.pt(pt)) mpghrhs (.hashin(exu_mp_addr[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]), .ghr(exu_mp_eghr[pt.BHT_GHR_SIZE-1:0]), .hash(mp_hashed[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO])); el2_btb_ghr_hash #(.pt(pt)) br0ghrhs (.hashin(dec_tlu_br0_addr_wb[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]), .ghr(exu_i0_br_fghr_wb[pt.BHT_GHR_SIZE-1:0]), .hash(br0_hashed_wb[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO])); el2_btb_ghr_hash #(.pt(pt)) fghrhs (.hashin(btb_rd_addr_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]), .ghr(fghr[pt.BHT_GHR_SIZE-1:0]), .hash(bht_rd_addr_hashed_f[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO])); el2_btb_ghr_hash #(.pt(pt)) fghrhs_p1 (.hashin(btb_rd_addr_p1_f[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO]), .ghr(fghr[pt.BHT_GHR_SIZE-1:0]), .hash(bht_rd_addr_hashed_p1_f[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO])); assign bht_wr_addr0[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] = mp_hashed[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO]; assign bht_wr_addr2[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] = br0_hashed_wb[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO]; assign bht_rd_addr_f[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] = bht_rd_addr_hashed_f[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO]; assign bht_rd_addr_p1_f[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] = bht_rd_addr_hashed_p1_f[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO]; // ---------------------------------------------------------------------- // Structures. Using FLOPS // ---------------------------------------------------------------------- // BTB // Entry -> tag[pt.BTB_BTAG_SIZE-1:0], toffset[11:0], pc4, boffset, call, ret, valid if(!pt.BTB_FULLYA) begin for (j=0 ; j direction, strength // //----------------------------------------------------------------------------- // logic [1:0] [(pt.BHT_ARRAY_DEPTH/NUM_BHT_LOOP)-1:0][NUM_BHT_LOOP-1:0][1:0] bht_bank_wr_data ; logic [1:0] [pt.BHT_ARRAY_DEPTH-1:0] [1:0] bht_bank_rd_data_out ; logic [1:0] [(pt.BHT_ARRAY_DEPTH/NUM_BHT_LOOP)-1:0] bht_bank_clken ; logic [1:0] [(pt.BHT_ARRAY_DEPTH/NUM_BHT_LOOP)-1:0] bht_bank_clk ; // logic [1:0] [(pt.BHT_ARRAY_DEPTH/NUM_BHT_LOOP)-1:0][NUM_BHT_LOOP-1:0] bht_bank_sel ; for ( i=0; i<2; i++) begin : BANKS wire[pt.BHT_ARRAY_DEPTH-1:0] wr0, wr1; assign wr0 = pt.BHT_ARRAY_DEPTH'(bht_wr_en0[i] << bht_wr_addr0); assign wr1 = pt.BHT_ARRAY_DEPTH'(bht_wr_en2[i] << bht_wr_addr2); for (genvar k=0 ; k < (pt.BHT_ARRAY_DEPTH)/NUM_BHT_LOOP ; k++) begin : BHT_CLK_GROUP assign bht_bank_clken[i][k] = (bht_wr_en0[i] & ((bht_wr_addr0[pt.BHT_ADDR_HI: NUM_BHT_LOOP_OUTER_LO]==k) | BHT_NO_ADDR_MATCH)) | (bht_wr_en2[i] & ((bht_wr_addr2[pt.BHT_ADDR_HI: NUM_BHT_LOOP_OUTER_LO]==k) | BHT_NO_ADDR_MATCH)); `ifndef RV_FPGA_OPTIMIZE rvclkhdr bht_bank_grp_cgc ( .en(bht_bank_clken[i][k]), .l1clk(bht_bank_clk[i][k]), .* ); // ifndef RV_FPGA_OPTIMIZE `else assign bht_bank_clk[i][k] = clk; `endif for (j=0 ; j cdecode.e // 2) espresso -Dso -oeqntott cdecode.e | addassign > compress_equations // to generate the legal (16b compressed instruction is legal) equation below: // 1) coredecode -in cdecode -legal > clegal.e // 2) espresso -Dso -oeqntott clegal.e | addassign > clegal_equation // espresso decodes assign rdrd = (!i[14]&i[6]&i[1]) | (!i[15]&i[14]&i[11]&i[0]) | (!i[14]&i[5]&i[1]) | ( !i[15]&i[14]&i[10]&i[0]) | (!i[14]&i[4]&i[1]) | (!i[15]&i[14]&i[9] &i[0]) | (!i[14]&i[3]&i[1]) | (!i[15]&i[14]&!i[8]&i[0]) | (!i[14] &i[2]&i[1]) | (!i[15]&i[14]&i[7]&i[0]) | (!i[15]&i[1]) | (!i[15] &!i[13]&i[0]); assign rdrs1 = (!i[14]&i[12]&i[11]&i[1]) | (!i[14]&i[12]&i[10]&i[1]) | (!i[14] &i[12]&i[9]&i[1]) | (!i[14]&i[12]&i[8]&i[1]) | (!i[14]&i[12]&i[7] &i[1]) | (!i[14]&!i[12]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14] &i[12]&i[6]&i[1]) | (!i[14]&i[12]&i[5]&i[1]) | (!i[14]&i[12]&i[4] &i[1]) | (!i[14]&i[12]&i[3]&i[1]) | (!i[14]&i[12]&i[2]&i[1]) | ( !i[15]&!i[14]&!i[13]&i[0]) | (!i[15]&!i[14]&i[1]); assign rs2rs2 = (i[15]&i[6]&i[1]) | (i[15]&i[5]&i[1]) | (i[15]&i[4]&i[1]) | ( i[15]&i[3]&i[1]) | (i[15]&i[2]&i[1]) | (i[15]&i[14]&i[1]); assign rdprd = (i[15]&!i[14]&!i[13]&i[0]); assign rdprs1 = (i[15]&!i[13]&i[0]) | (i[15]&i[14]&i[0]) | (i[14]&!i[1]&!i[0]); assign rs2prs2 = (i[15]&!i[14]&!i[13]&i[11]&i[10]&i[0]) | (i[15]&!i[1]&!i[0]); assign rs2prd = (!i[15]&!i[1]&!i[0]); assign uimm9_2 = (!i[14]&!i[1]&!i[0]); assign ulwimm6_2 = (!i[15]&i[14]&!i[1]&!i[0]); assign ulwspimm7_2 = (!i[15]&i[14]&i[1]); assign rdeq2 = (!i[15]&i[14]&i[13]&!i[11]&!i[10]&!i[9]&i[8]&!i[7]); assign rdeq1 = (!i[14]&i[12]&i[11]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14] &i[12]&i[10]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[9] &!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[8]&!i[6]&!i[5] &!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[7]&!i[6]&!i[5]&!i[4]&!i[3] &!i[2]&i[1]) | (!i[15]&!i[14]&i[13]); assign rs1eq2 = (!i[15]&i[14]&i[13]&!i[11]&!i[10]&!i[9]&i[8]&!i[7]) | (i[14] &i[1]) | (!i[14]&!i[1]&!i[0]); assign sbroffset8_1 = (i[15]&i[14]&i[0]); assign simm9_4 = (!i[15]&i[14]&i[13]&!i[11]&!i[10]&!i[9]&i[8]&!i[7]); assign simm5_0 = (!i[14]&!i[13]&i[11]&!i[10]&i[0]) | (!i[15]&!i[13]&i[0]); assign sjaloffset11_1 = (!i[14]&i[13]); assign sluimm17_12 = (!i[15]&i[14]&i[13]&i[7]) | (!i[15]&i[14]&i[13]&!i[8]) | ( !i[15]&i[14]&i[13]&i[9]) | (!i[15]&i[14]&i[13]&i[10]) | (!i[15]&i[14] &i[13]&i[11]); assign uimm5_0 = (i[15]&!i[14]&!i[13]&!i[11]&i[0]) | (!i[15]&!i[14]&i[1]); assign uswimm6_2 = (i[15]&!i[1]&!i[0]); assign uswspimm7_2 = (i[15]&i[14]&i[1]); assign o[31] = 1'b0; assign o[30] = (i[15]&!i[14]&!i[13]&i[10]&!i[6]&!i[5]&i[0]) | (i[15]&!i[14] &!i[13]&!i[11]&i[10]&i[0]); assign o[29] = 1'b0; assign o[28] = 1'b0; assign o[27] = 1'b0; assign o[26] = 1'b0; assign o[25] = 1'b0; assign o[24] = 1'b0; assign o[23] = 1'b0; assign o[22] = 1'b0; assign o[21] = 1'b0; assign o[20] = (!i[14]&i[12]&!i[11]&!i[10]&!i[9]&!i[8]&!i[7]&!i[6]&!i[5]&!i[4] &!i[3]&!i[2]&i[1]); assign o[19] = 1'b0; assign o[18] = 1'b0; assign o[17] = 1'b0; assign o[16] = 1'b0; assign o[15] = 1'b0; assign o[14] = (i[15]&!i[14]&!i[13]&!i[11]&i[0]) | (i[15]&!i[14]&!i[13]&!i[10] &i[0]) | (i[15]&!i[14]&!i[13]&i[6]&i[0]) | (i[15]&!i[14]&!i[13]&i[5] &i[0]); assign o[13] = (i[15]&!i[14]&!i[13]&i[11]&!i[10]&i[0]) | (i[15]&!i[14]&!i[13] &i[11]&i[6]&i[0]) | (i[14]&!i[0]); assign o[12] = (i[15]&!i[14]&!i[13]&i[6]&i[5]&i[0]) | (i[15]&!i[14]&!i[13]&!i[11] &i[0]) | (i[15]&!i[14]&!i[13]&!i[10]&i[0]) | (!i[15]&!i[14]&i[1]) | ( i[15]&i[14]&i[13]); assign o[11] = 1'b0; assign o[10] = 1'b0; assign o[9] = 1'b0; assign o[8] = 1'b0; assign o[7] = 1'b0; assign o[6] = (i[15]&!i[14]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&!i[0]) | (!i[14]&i[13]) | ( i[15]&i[14]&i[0]); assign o[5] = (i[15]&!i[0]) | (i[15]&i[11]&i[10]) | (i[13]&!i[8]) | (i[13]&i[7]) | ( i[13]&i[9]) | (i[13]&i[10]) | (i[13]&i[11]) | (!i[14]&i[13]) | ( i[15]&i[14]); assign o[4] = (!i[14]&!i[11]&!i[10]&!i[9]&!i[8]&!i[7]&!i[0]) | (!i[15]&!i[14] &!i[0]) | (!i[14]&i[6]&!i[0]) | (!i[15]&i[14]&i[0]) | (!i[14]&i[5] &!i[0]) | (!i[14]&i[4]&!i[0]) | (!i[14]&!i[13]&i[0]) | (!i[14]&i[3] &!i[0]) | (!i[14]&i[2]&!i[0]); assign o[3] = (!i[14]&i[13]); assign o[2] = (!i[14]&i[12]&i[11]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14] &i[12]&i[10]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[9] &!i[6]&!i[5]&!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[8]&!i[6]&!i[5] &!i[4]&!i[3]&!i[2]&i[1]) | (!i[14]&i[12]&i[7]&!i[6]&!i[5]&!i[4]&!i[3] &!i[2]&i[1]) | (i[15]&!i[14]&!i[12]&!i[6]&!i[5]&!i[4]&!i[3]&!i[2] &!i[0]) | (!i[15]&i[13]&!i[8]) | (!i[15]&i[13]&i[7]) | (!i[15]&i[13] &i[9]) | (!i[15]&i[13]&i[10]) | (!i[15]&i[13]&i[11]) | (!i[14]&i[13]); // 32b instruction has lower two bits 2'b11 assign o[1] = 1'b1; assign o[0] = 1'b1; assign legal = (!i[13]&!i[12]&i[11]&i[1]&!i[0]) | (!i[13]&!i[12]&i[10]&i[1]&!i[0]) | ( !i[15]&!i[13]&i[11]&!i[1]) | (!i[13]&!i[12]&i[9]&i[1]&!i[0]) | ( !i[13]&!i[12]&i[8]&i[1]&!i[0]) | (!i[15]&!i[13]&i[6]&!i[1]) | (i[15] &!i[12]&!i[1]&i[0]) | (!i[13]&!i[12]&i[7]&i[1]&!i[0]) | (!i[15]&!i[13] &i[5]&!i[1]) | (!i[12]&i[6]&!i[1]&i[0]) | (i[15]&!i[13]&i[6]&i[1] &!i[0]) | (!i[15]&!i[13]&i[10]&!i[1]) | (!i[12]&i[5]&!i[1]&i[0]) | ( i[12]&i[11]&!i[10]&!i[1]&i[0]) | (i[15]&!i[13]&i[5]&i[1]&!i[0]) | ( !i[15]&!i[13]&i[9]&!i[1]) | (i[13]&i[12]&!i[1]&i[0]) | (i[15]&!i[13] &i[4]&i[1]&!i[0]) | (!i[15]&!i[13]&i[8]&!i[1]) | (i[15]&!i[13]&i[3] &i[1]&!i[0]) | (i[13]&i[4]&!i[1]&i[0]) | (i[15]&!i[13]&i[2]&i[1]&!i[0]) | ( !i[15]&!i[13]&i[7]&!i[1]) | (i[13]&i[3]&!i[1]&i[0]) | (i[13]&i[2] &!i[1]&i[0]) | (!i[14]&!i[12]&!i[1]&i[0]) | (i[15]&!i[13]&i[12]&i[1] &!i[0]) | (i[14]&!i[13]&i[7]&!i[0]) | (i[14]&!i[13]&i[8]&!i[0]) | ( i[14]&!i[13]&i[9]&!i[0]) | (!i[15]&!i[14]&!i[13]&!i[12]&i[1]&!i[0]) | ( i[14]&!i[13]&i[10]&!i[0]) | (i[14]&!i[13]&i[11]&!i[0]) | (!i[15] &!i[13]&i[12]&!i[1]) | (i[15]&i[14]&!i[13]&!i[0]) | (i[14]&!i[13] &!i[1]); endmodule ================================================ FILE: design/ifu/el2_ifu_ic_mem.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** //////////////////////////////////////////////////// // ICACHE DATA & TAG MODULE WRAPPER // ///////////////////////////////////////////////////// module el2_ifu_ic_mem import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic rst_l, // reset, active low input logic clk_override, // Override non-functional clock gating input logic dec_tlu_core_ecc_disable, // Disable ECC checking input logic [31:1] ic_rw_addr, input logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en , // Which way to write input logic ic_rd_en , // Read enable input logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. input logic ic_debug_rd_en, // Icache debug rd input logic ic_debug_wr_en, // Icache debug wr input logic ic_debug_tag_array, // Debug tag array input logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. input logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache. input logic ic_sel_premux_data, // Select the pre_muxed data input logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC output logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC output logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC output logic [25:0] ictag_debug_rd_data,// Debug icache tag. input logic [70:0] ic_debug_wr_data, // Debug wr cache. output logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, // ecc error per bank output logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, // ecc error per bank input logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid, // Valid from the I$ tag valid outside (in flops). el2_mem_if.veer_icache_src icache_export, output logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, // ic_rd_hit[3:0] output logic ic_tag_perr, // Tag Parity error // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // Flop scan mode control /*pragma coverage on*/ ) ; // split the veer_icache_src interface into veer_icache_data and veer_icache_tag el2_mem_if local_icache_export(); always_comb begin // data icache_export.ic_b_sb_wren = local_icache_export.ic_b_sb_wren; icache_export.ic_b_sb_bit_en_vec = local_icache_export.ic_b_sb_bit_en_vec; icache_export.ic_sb_wr_data = local_icache_export.ic_sb_wr_data; icache_export.ic_rw_addr_bank_q = local_icache_export.ic_rw_addr_bank_q; icache_export.ic_bank_way_clken_final = local_icache_export.ic_bank_way_clken_final; icache_export.ic_bank_way_clken_final_up = local_icache_export.ic_bank_way_clken_final_up; local_icache_export.wb_packeddout_pre = icache_export.wb_packeddout_pre; local_icache_export.wb_dout_pre_up = icache_export.wb_dout_pre_up; // tag icache_export.ic_tag_clken_final = local_icache_export.ic_tag_clken_final; icache_export.ic_tag_wren_q = local_icache_export.ic_tag_wren_q; icache_export.ic_tag_wren_biten_vec = local_icache_export.ic_tag_wren_biten_vec; icache_export.ic_tag_wr_data = local_icache_export.ic_tag_wr_data; icache_export.ic_rw_addr_q = local_icache_export.ic_rw_addr_q; local_icache_export.ic_tag_data_raw_pre = icache_export.ic_tag_data_raw_pre; local_icache_export.ic_tag_data_raw_packed_pre = icache_export.ic_tag_data_raw_packed_pre; end EL2_IC_TAG #(.pt(pt)) ic_tag_inst ( .*, .icache_export(local_icache_export.veer_icache_tag), .ic_wr_en (ic_wr_en[pt.ICACHE_NUM_WAYS-1:0]), .ic_debug_addr(ic_debug_addr[pt.ICACHE_INDEX_HI:3]), .ic_rw_addr (ic_rw_addr[31:3]) ) ; EL2_IC_DATA #(.pt(pt)) ic_data_inst ( .*, .icache_export(local_icache_export.veer_icache_data), .ic_wr_en (ic_wr_en[pt.ICACHE_NUM_WAYS-1:0]), .ic_debug_addr(ic_debug_addr[pt.ICACHE_INDEX_HI:3]), .ic_rw_addr (ic_rw_addr[31:1]) ) ; endmodule ///////////////////////////////////////////////// ////// ICACHE DATA MODULE //////////////////// ///////////////////////////////////////////////// module EL2_IC_DATA import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic active_clk, input logic rst_l, input logic clk_override, input logic [31:1] ic_rw_addr, input logic [pt.ICACHE_NUM_WAYS-1:0]ic_wr_en, input logic ic_rd_en, // Read enable input logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC output logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [70:0] ic_debug_wr_data, // Debug wr cache. output logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC output logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, output logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, // ecc error per bank input logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. input logic ic_debug_rd_en, // Icache debug rd input logic ic_debug_wr_en, // Icache debug wr input logic ic_debug_tag_array, // Debug tag array input logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. input logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache. input logic ic_sel_premux_data, // Select the pre_muxed data input logic [pt.ICACHE_NUM_WAYS-1:0]ic_rd_hit, el2_mem_if.veer_icache_data icache_export, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ) ; logic [pt.ICACHE_TAG_INDEX_LO-1:1] ic_rw_addr_ff; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_WAYS-1:0] ic_b_sb_wren; //bank x ways logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_WAYS-1:0] ic_b_sb_rden; //bank x ways logic [pt.ICACHE_BANKS_WAY-1:0] ic_b_rden; //bank logic [pt.ICACHE_BANKS_WAY-1:0] ic_b_rden_ff; //bank logic [pt.ICACHE_BANKS_WAY-1:0] ic_debug_sel_sb; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][70:0] wb_dout ; // ways x bank logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_sb_wr_data, ic_bank_wr_data, wb_dout_ecc_bank; logic [pt.ICACHE_NUM_WAYS-1:0] [141:0] wb_dout_way_pre; logic [pt.ICACHE_NUM_WAYS-1:0] [63:0] wb_dout_way, wb_dout_way_with_premux; logic [141:0] wb_dout_ecc; logic [pt.ICACHE_BANKS_WAY-1:0] bank_check_en; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_WAYS-1:0] ic_bank_way_clken; logic [pt.ICACHE_BANKS_WAY-1:0] ic_bank_way_clken_final; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_bank_way_clken_final_up; logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_rd_way_en; // debug wr_way logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_rd_way_en_ff; // debug wr_way logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_wr_way_en; // debug wr_way logic [pt.ICACHE_INDEX_HI:1] ic_rw_addr_q; logic [pt.ICACHE_BANKS_WAY-1:0] [pt.ICACHE_INDEX_HI : pt.ICACHE_DATA_INDEX_LO] ic_rw_addr_bank_q; logic [pt.ICACHE_TAG_LO-1 : pt.ICACHE_DATA_INDEX_LO] ic_rw_addr_q_inc; logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit_q; logic [pt.ICACHE_BANKS_WAY-1:0] ic_b_sram_en; logic [pt.ICACHE_BANKS_WAY-1:0] ic_b_read_en; logic [pt.ICACHE_BANKS_WAY-1:0] ic_b_write_en; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] [31 : pt.ICACHE_DATA_INDEX_LO] wb_index_hold; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] write_bypass_en; //bank logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] write_bypass_en_ff; //bank logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] index_valid; //bank logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_clear_en; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_addr_match; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_addr_match_index_only; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_b_sram_en_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_b_read_en_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_b_write_en_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] [31 : pt.ICACHE_DATA_INDEX_LO] wb_index_hold_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] write_bypass_en_up; //bank logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] write_bypass_en_ff_up; //bank logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] index_valid_up; //bank logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_clear_en_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_addr_match_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_addr_match_index_only_up; logic [pt.ICACHE_BANKS_WAY-1:0] [31 : pt.ICACHE_DATA_INDEX_LO] ic_b_rw_addr; logic [pt.ICACHE_BANKS_WAY-1:0] [pt.ICACHE_INDEX_HI : pt.ICACHE_DATA_INDEX_LO] ic_b_rw_addr_index_only; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] [31 : pt.ICACHE_DATA_INDEX_LO] ic_b_rw_addr_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] [pt.ICACHE_INDEX_HI : pt.ICACHE_DATA_INDEX_LO] ic_b_rw_addr_index_only_up; logic ic_rd_en_with_debug; logic ic_rw_addr_wrap, ic_cacheline_wrap_ff; logic ic_debug_rd_en_ff; // Use exported ICache interface. Some signals are assigned here, some in the blocks below. always_comb begin icache_export.ic_b_sb_wren = ic_b_sb_wren; icache_export.ic_sb_wr_data = ic_sb_wr_data; icache_export.ic_rw_addr_bank_q = ic_rw_addr_bank_q; icache_export.ic_bank_way_clken_final =ic_bank_way_clken_final; icache_export.ic_bank_way_clken_final_up =ic_bank_way_clken_final_up; end //----------------------------------------------------------- // ----------- Logic section starts here -------------------- //----------------------------------------------------------- assign ic_debug_rd_way_en[pt.ICACHE_NUM_WAYS-1:0] = {pt.ICACHE_NUM_WAYS{ic_debug_rd_en & ~ic_debug_tag_array}} & ic_debug_way[pt.ICACHE_NUM_WAYS-1:0] ; assign ic_debug_wr_way_en[pt.ICACHE_NUM_WAYS-1:0] = {pt.ICACHE_NUM_WAYS{ic_debug_wr_en & ~ic_debug_tag_array}} & ic_debug_way[pt.ICACHE_NUM_WAYS-1:0] ; logic end_of_cache_line; assign end_of_cache_line = (pt.ICACHE_LN_SZ==7'h40) ? (&ic_rw_addr_q[5:4]) : ic_rw_addr_q[4]; always_comb begin : clkens ic_bank_way_clken = '0; for ( int i=0; i // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** //******************************************************************************** // Icache closely coupled memory --- ICCM //******************************************************************************** module el2_ifu_iccm_mem import el2_pkg::*; #( `include "el2_param.vh" )( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic rst_l, // reset, active low input logic clk_override, // Override non-functional clock gating input logic iccm_wren, // ICCM write enable input logic iccm_rden, // ICCM read enable input logic [pt.ICCM_BITS-1:1] iccm_rw_addr, // ICCM read/write address input logic iccm_buf_correct_ecc, // ICCM is doing a single bit error correct cycle input logic iccm_correction_state, // ICCM under a correction - This is needed to guard replacements when hit input logic [2:0] iccm_wr_size, // ICCM write size input logic [77:0] iccm_wr_data, // ICCM write data el2_mem_if.veer_iccm iccm_mem_export, // RAM repositioned in testbench and connected by this interface output logic [63:0] iccm_rd_data, // ICCM read data output logic [77:0] iccm_rd_data_ecc, // ICCM read ecc // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // Scan mode control /*pragma coverage on*/ ); logic [pt.ICCM_NUM_BANKS-1:0] wren_bank; logic [pt.ICCM_NUM_BANKS-1:0] rden_bank; logic [pt.ICCM_NUM_BANKS-1:0] iccm_clken; logic [pt.ICCM_NUM_BANKS-1:0] [pt.ICCM_BITS-1:pt.ICCM_BANK_INDEX_LO] addr_bank; logic [pt.ICCM_NUM_BANKS-1:0] [38:0] iccm_bank_dout, iccm_bank_dout_fn; logic [pt.ICCM_NUM_BANKS-1:0] [38:0] iccm_bank_wr_data; logic [pt.ICCM_BITS-1:1] addr_bank_inc; logic [pt.ICCM_BANK_HI : 2] iccm_rd_addr_hi_q; logic [pt.ICCM_BANK_HI : 1] iccm_rd_addr_lo_q; logic [63:0] iccm_rd_data_pre; logic [63:0] iccm_data; logic [1:0] addr_incr; logic [pt.ICCM_NUM_BANKS-1:0] [38:0] iccm_bank_wr_data_vec; // logic to handle hard persisten faults logic [1:0] [pt.ICCM_BITS-1:2] redundant_address; logic [1:0] [38:0] redundant_data; logic [1:0] redundant_valid; logic [pt.ICCM_NUM_BANKS-1:0] sel_red1, sel_red0, sel_red1_q, sel_red0_q; logic [38:0] redundant_data0_in, redundant_data1_in; logic redundant_lru, redundant_lru_in, redundant_lru_en; logic redundant_data0_en; logic redundant_data1_en; logic r0_addr_en, r1_addr_en; // Testing persistent flip // logic [3:0] not_iccm_bank_dout; // logic [15:3] ecc_insert_flip_in, ecc_insert_flip; // logic flip_en, flip_match, flip_match_q; // // assign flip_in = (iccm_rw_addr[3:2] != 2'b00); // dont flip when bank0 - this is to make some progress in DMA streaming cases // assign flip_en = iccm_rden; // // rvdffs #(1) flipmatch (.*, // .clk(clk), // .din(flip_in), // .en(flip_en), // .dout(flip_match_q)); // // end of testing flip assign addr_incr[1:0] = (iccm_wr_size[1:0] == 2'b11) ? 2'b10: 2'b01; assign addr_bank_inc[pt.ICCM_BITS-1 : 1] = iccm_rw_addr[pt.ICCM_BITS-1 : 1] + addr_incr[1:0]; for (genvar i=0; i> (16*iccm_rd_addr_lo_q[1]))}); assign iccm_rd_data[63:0] = {iccm_data[63:0]}; assign iccm_rd_data_ecc[77:0] = {iccm_bank_dout_fn[iccm_rd_addr_hi_q][38:0], iccm_bank_dout_fn[iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:2]][38:0]}; endmodule // el2_ifu_iccm_mem ================================================ FILE: design/ifu/el2_ifu_ifc_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // el2_ifu_ifc_ctl.sv // Function: Fetch pipe control // // Comments: //******************************************************************************** module el2_ifu_ifc_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in. input logic rst_l, // reset enable, from core pin // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // scan /*pragma coverage on*/ input logic ic_hit_f, // Icache hit input logic ifu_ic_mb_empty, // Miss buffer empty input logic ifu_fb_consume1, // Aligner consumed 1 fetch buffer input logic ifu_fb_consume2, // Aligner consumed 2 fetch buffers input logic dec_tlu_flush_noredir_wb, // Don't fetch on flush input logic exu_flush_final, // FLush input logic [31:1] exu_flush_path_final, // Flush path input logic ifu_bp_hit_taken_f, // btb hit, select the target path input logic [31:1] ifu_bp_btb_target_f, // predicted target PC input logic ic_dma_active, // IC DMA active, stop fetching input logic ic_write_stall, // IC is writing, stop fetching input logic dma_iccm_stall_any, // force a stall in the fetch pipe for DMA ICCM access input logic [31:0] dec_tlu_mrac_ff , // side_effect and cacheable for each region output logic [31:1] ifc_fetch_addr_f, // fetch addr F output logic [31:1] ifc_fetch_addr_bf, // fetch addr BF output logic ifc_fetch_req_f, // fetch request valid F output logic ifu_pmu_fetch_stall, // pmu event measuring fetch stall output logic ifc_fetch_uncacheable_bf, // The fetch request is uncacheable space. BF stage output logic ifc_fetch_req_bf, // Fetch request. Comes with the address. BF stage output logic ifc_fetch_req_bf_raw, // Fetch request without some qualifications. Used for clock-gating. BF stage output logic ifc_iccm_access_bf, // This request is to the ICCM. Do not generate misses to the bus. output logic ifc_region_acc_fault_bf, // Access fault. in ICCM region but offset is outside defined ICCM. output logic ifc_dma_access_ok // fetch is not accessing the ICCM, DMA can proceed ); logic [31:1] fetch_addr_bf; logic [31:1] fetch_addr_next; logic [3:0] fb_write_f, fb_write_ns; logic fb_full_f_ns, fb_full_f; logic fb_right, fb_right2, fb_left, wfm, idle; logic sel_last_addr_bf, sel_next_addr_bf; logic miss_f, miss_a; logic flush_fb, dma_iccm_stall_any_f; logic mb_empty_mod, goto_idle, leave_idle; logic fetch_bf_en; logic line_wrap; logic fetch_addr_next_1; // FSM assignment typedef enum logic [1:0] { IDLE = 2'b00 , FETCH = 2'b01 , STALL = 2'b10 , WFM = 2'b11 } state_t ; state_t state ; state_t next_state ; logic dma_stall; assign dma_stall = ic_dma_active | dma_iccm_stall_any_f; // Fetch address mux // - flush // - Miss *or* flush during WFM (icache miss buffer is blocking) // - Sequential if(pt.BTB_ENABLE==1) begin : genblock1 logic sel_btb_addr_bf; assign sel_last_addr_bf = ~exu_flush_final & (~ifc_fetch_req_f | ~ic_hit_f); assign sel_btb_addr_bf = ~exu_flush_final & ifc_fetch_req_f & ifu_bp_hit_taken_f & ic_hit_f; assign sel_next_addr_bf = ~exu_flush_final & ifc_fetch_req_f & ~ifu_bp_hit_taken_f & ic_hit_f; assign fetch_addr_bf[31:1] = ( ({31{exu_flush_final}} & exu_flush_path_final[31:1]) | // FLUSH path ({31{sel_last_addr_bf}} & ifc_fetch_addr_f[31:1]) | // MISS path ({31{sel_btb_addr_bf}} & {ifu_bp_btb_target_f[31:1]})| // BTB target ({31{sel_next_addr_bf}} & {fetch_addr_next[31:1]})); // SEQ path end // if (pt.BTB_ENABLE=1) else begin assign sel_last_addr_bf = ~exu_flush_final & (~ifc_fetch_req_f | ~ic_hit_f); assign sel_next_addr_bf = ~exu_flush_final & ifc_fetch_req_f & ic_hit_f; assign fetch_addr_bf[31:1] = ( ({31{exu_flush_final}} & exu_flush_path_final[31:1]) | // FLUSH path ({31{sel_last_addr_bf}} & ifc_fetch_addr_f[31:1]) | // MISS path ({31{sel_next_addr_bf}} & {fetch_addr_next[31:1]})); // SEQ path end assign fetch_addr_next[31:1] = {({ifc_fetch_addr_f[31:2]} + 30'b1), fetch_addr_next_1 }; assign line_wrap = (fetch_addr_next[pt.ICACHE_TAG_INDEX_LO] ^ ifc_fetch_addr_f[pt.ICACHE_TAG_INDEX_LO]); assign fetch_addr_next_1 = line_wrap ? 1'b0 : ifc_fetch_addr_f[1]; assign ifc_fetch_req_bf_raw = ~idle; assign ifc_fetch_req_bf = ifc_fetch_req_bf_raw & ~(fb_full_f_ns & ~(ifu_fb_consume2 | ifu_fb_consume1)) & ~dma_stall & ~ic_write_stall & ~dec_tlu_flush_noredir_wb; assign fetch_bf_en = exu_flush_final | ifc_fetch_req_f; assign miss_f = ifc_fetch_req_f & ~ic_hit_f & ~exu_flush_final; assign mb_empty_mod = (ifu_ic_mb_empty | exu_flush_final) & ~dma_stall & ~miss_f & ~miss_a; // Halt flushes and takes us to IDLE assign goto_idle = exu_flush_final & dec_tlu_flush_noredir_wb; // If we're in IDLE, and we get a flush, goto FETCH assign leave_idle = exu_flush_final & ~dec_tlu_flush_noredir_wb & idle; //.i 7 //.o 2 //.ilb state[1] state[0] reset_delayed miss_f mb_empty_mod goto_idle leave_idle //.ob next_state[1] next_state[0] //.type fr // //# fetch 01, stall 10, wfm 11, idle 00 //-- 1---- 01 //-- 0--1- 00 //00 0--00 00 //00 0--01 01 // //01 01-0- 11 //01 00-0- 01 // //11 0-10- 01 //11 0-00- 11 assign next_state[1] = (~state[1] & state[0] & miss_f & ~goto_idle) | (state[1] & ~mb_empty_mod & ~goto_idle); assign next_state[0] = (~goto_idle & leave_idle) | (state[0] & ~goto_idle); assign flush_fb = exu_flush_final; // model fb write logic to mass balance the fetch buffers assign fb_right = ( ifu_fb_consume1 & ~ifu_fb_consume2 & (~ifc_fetch_req_f | miss_f)) | // Consumed and no new fetch (ifu_fb_consume2 & ifc_fetch_req_f); // Consumed 2 and new fetch assign fb_right2 = (ifu_fb_consume2 & (~ifc_fetch_req_f | miss_f)); // Consumed 2 and no new fetch assign fb_left = ifc_fetch_req_f & ~(ifu_fb_consume1 | ifu_fb_consume2) & ~miss_f; // CBH assign fb_write_ns[3:0] = ( ({4{(flush_fb)}} & 4'b0001) | ({4{~flush_fb & fb_right }} & {1'b0, fb_write_f[3:1]}) | ({4{~flush_fb & fb_right2}} & {2'b0, fb_write_f[3:2]}) | ({4{~flush_fb & fb_left }} & {fb_write_f[2:0], 1'b0}) | ({4{~flush_fb & ~fb_right & ~fb_right2 & ~fb_left}} & fb_write_f[3:0])); assign fb_full_f_ns = fb_write_ns[3]; assign idle = state == IDLE ; assign wfm = state == WFM ; rvdffie #(10) fbwrite_ff (.*, .clk(free_l2clk), .din( {dma_iccm_stall_any, miss_f, ifc_fetch_req_bf, next_state[1:0], fb_full_f_ns, fb_write_ns[3:0]}), .dout({dma_iccm_stall_any_f, miss_a, ifc_fetch_req_f, state[1:0], fb_full_f, fb_write_f[3:0]})); assign ifu_pmu_fetch_stall = wfm | (ifc_fetch_req_bf_raw & ( (fb_full_f & ~(ifu_fb_consume2 | ifu_fb_consume1 | exu_flush_final)) | dma_stall)); assign ifc_fetch_addr_bf[31:1] = fetch_addr_bf[31:1]; rvdffpcie #(31) faddrf1_ff (.*, .en(fetch_bf_en), .din(fetch_addr_bf[31:1]), .dout(ifc_fetch_addr_f[31:1])); if (pt.ICCM_ENABLE) begin : genblock2 logic iccm_acc_in_region_bf; logic iccm_acc_in_range_bf; rvrangecheck #( .CCM_SADR (pt.ICCM_SADR), .CCM_SIZE (pt.ICCM_SIZE) ) iccm_rangecheck ( .addr ({ifc_fetch_addr_bf[31:1],1'b0}) , .in_range (iccm_acc_in_range_bf) , .in_region(iccm_acc_in_region_bf) ); assign ifc_iccm_access_bf = iccm_acc_in_range_bf ; assign ifc_dma_access_ok = ( (~ifc_iccm_access_bf | (fb_full_f & ~(ifu_fb_consume2 | ifu_fb_consume1)) | (wfm & ~ifc_fetch_req_bf) | idle ) & ~exu_flush_final) | dma_iccm_stall_any_f; assign ifc_region_acc_fault_bf = ~iccm_acc_in_range_bf & iccm_acc_in_region_bf ; end else begin assign ifc_iccm_access_bf = 1'b0 ; assign ifc_dma_access_ok = 1'b0 ; assign ifc_region_acc_fault_bf = 1'b0 ; end assign ifc_fetch_uncacheable_bf = ~dec_tlu_mrac_ff[{ifc_fetch_addr_bf[31:28] , 1'b0 }] ; // bit 0 of each region description is the cacheable bit endmodule // el2_ifu_ifc_ctl ================================================ FILE: design/ifu/el2_ifu_mem_ctl.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** //******************************************************************************** // Function: Icache , iccm control // BFF -> F1 -> F2 -> A //******************************************************************************** module el2_ifu_mem_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in. input logic rst_l, // reset, active low input logic exu_flush_final, // Flush from the pipeline., includes flush lower input logic dec_tlu_flush_lower_wb, // Flush lower from the pipeline. input logic dec_tlu_flush_err_wb, // Flush from the pipeline due to perr. input logic dec_tlu_i0_commit_cmt, // committed i0 instruction input logic dec_tlu_force_halt, // force halt. input logic [31:1] ifc_fetch_addr_bf, // Fetch Address byte aligned always. F1 stage. input logic ifc_fetch_uncacheable_bf, // The fetch request is uncacheable space. F1 stage input logic ifc_fetch_req_bf, // Fetch request. Comes with the address. F1 stage input logic ifc_fetch_req_bf_raw, // Fetch request without some qualifications. Used for clock-gating. F1 stage input logic ifc_iccm_access_bf, // This request is to the ICCM. Do not generate misses to the bus. input logic ifc_region_acc_fault_bf, // Access fault. in ICCM region but offset is outside defined ICCM. input logic ifc_dma_access_ok, // It is OK to give dma access to the ICCM. (ICCM is not busy this cycle). input logic dec_tlu_fence_i_wb, // Fence.i instruction is committing. Clear all Icache valids. input logic ifu_bp_hit_taken_f, // Branch is predicted taken. Kill the fetch next cycle. input logic ifu_bp_inst_mask_f, // tell ic which valids to kill because of a taken branch, right justified output logic ifu_miss_state_idle, // No icache misses are outstanding. output logic ifu_ic_mb_empty, // Continue with normal fetching. This does not mean that miss is finished. output logic ic_dma_active , // In the middle of servicing dma request to ICCM. Do not make any new requests. output logic ic_write_stall, // Stall fetch the cycle we are writing the cache. /// PMU signals output logic ifu_pmu_ic_miss, // IC miss event output logic ifu_pmu_ic_hit, // IC hit event output logic ifu_pmu_bus_error, // Bus error event output logic ifu_pmu_bus_busy, // Bus busy event output logic ifu_pmu_bus_trxn, // Bus transaction //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic ifu_axi_awvalid, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid, output logic [31:0] ifu_axi_awaddr, output logic [3:0] ifu_axi_awregion, output logic [7:0] ifu_axi_awlen, output logic [2:0] ifu_axi_awsize, output logic [1:0] ifu_axi_awburst, output logic ifu_axi_awlock, output logic [3:0] ifu_axi_awcache, output logic [2:0] ifu_axi_awprot, output logic [3:0] ifu_axi_awqos, output logic ifu_axi_wvalid, output logic [63:0] ifu_axi_wdata, output logic [7:0] ifu_axi_wstrb, output logic ifu_axi_wlast, output logic ifu_axi_bready, /*pragma coverage on*/ // AXI Read Channels output logic ifu_axi_arvalid, input logic ifu_axi_arready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid, output logic [31:0] ifu_axi_araddr, output logic [3:0] ifu_axi_arregion, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [7:0] ifu_axi_arlen, output logic [2:0] ifu_axi_arsize, output logic [1:0] ifu_axi_arburst, output logic ifu_axi_arlock, output logic [3:0] ifu_axi_arcache, output logic [2:0] ifu_axi_arprot, output logic [3:0] ifu_axi_arqos, /*pragma coverage on*/ input logic ifu_axi_rvalid, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic ifu_axi_rready, /*pragma coverage on*/ input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid, input logic [63:0] ifu_axi_rdata, input logic [1:0] ifu_axi_rresp, input logic ifu_bus_clk_en, input logic dma_iccm_req, // dma iccm command (read or write) input logic [31:0] dma_mem_addr, // dma address input logic [2:0] dma_mem_sz, // size input logic dma_mem_write, // write input logic [63:0] dma_mem_wdata, // write data input logic [2:0] dma_mem_tag, // DMA Buffer entry number output logic iccm_dma_ecc_error,// Data read from iccm has an ecc error output logic iccm_dma_rvalid, // Data read from iccm is valid output logic [63:0] iccm_dma_rdata, // dma data read from iccm output logic [2:0] iccm_dma_rtag, // Tag of the DMA req output logic iccm_ready, // iccm ready to accept new command. // I$ & ITAG Ports output logic [31:1] ic_rw_addr, // Read/Write addresss to the Icache. output logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en, // Icache write enable, when filling the Icache. output logic ic_rd_en, // Icache read enable. output logic [pt.ICACHE_BANKS_WAY-1:0] [70:0] ic_wr_data, // Data to fill to the Icache. With ECC input logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [25:0] ictag_debug_rd_data, // Debug icache tag. output logic [70:0] ic_debug_wr_data, // Debug wr cache. output logic [70:0] ifu_ic_debug_rd_data, // debug data read input logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, // input logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, output logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. output logic ic_debug_rd_en, // Icache debug rd output logic ic_debug_wr_en, // Icache debug wr output logic ic_debug_tag_array, // Debug tag array output logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. output logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid, // Valid bits when accessing the Icache. One valid bit per way. F2 stage input logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, // Compare hits from Icache tags. Per way. F2 stage input logic ic_tag_perr, // Icache Tag parity error // ICCM ports output logic [pt.ICCM_BITS-1:1] iccm_rw_addr, // ICCM read/write address. output logic iccm_wren, // ICCM write enable (through the DMA) output logic iccm_rden, // ICCM read enable. output logic [77:0] iccm_wr_data, // ICCM write data. output logic [2:0] iccm_wr_size, // ICCM write location within DW. input logic [63:0] iccm_rd_data, // Data read from ICCM. input logic [77:0] iccm_rd_data_ecc, // Data + ECC read from ICCM. input logic [1:0] ifu_fetch_val, // IFU control signals output logic ic_hit_f, // Hit in Icache(if Icache access) or ICCM access( ICCM always has ic_hit_f) output logic [1:0] ic_access_fault_f, // Access fault (bus error or ICCM access in region but out of offset range). output logic [1:0] ic_access_fault_type_f, // Access fault types output logic iccm_rd_ecc_single_err, // This fetch has a single ICCM ECC error. output logic [1:0] iccm_rd_ecc_double_err, // This fetch has a double ICCM ECC error. output logic iccm_dma_rd_ecc_single_err, // This fetch has a single ICCM DMA ECC error. output logic iccm_dma_rd_ecc_double_err, // This fetch has a double ICCM DMA ECC error. output logic ic_error_start, // This has any I$ errors ( data/tag/ecc/parity ) output logic ifu_async_error_start, // Or of the sb iccm, and all the icache errors sent to aligner to stop output logic iccm_dma_sb_error, // Single Bit ECC error from a DMA access output logic [1:0] ic_fetch_val_f, // valid bytes for fetch. To the Aligner. output logic [31:0] ic_data_f, // Data read from Icache or ICCM. To the Aligner. output logic [63:0] ic_premux_data, // Premuxed data to be muxed with Icache data output logic ic_sel_premux_data, // Select premux data. ///// Debug input el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt , // Icache/tag debug read/write packet input logic dec_tlu_core_ecc_disable, // disable the ecc checking and flagging output logic ifu_ic_debug_rd_data_valid, // debug data valid. output logic iccm_buf_correct_ecc, output logic iccm_correction_state, input logic ifu_pmp_error, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); // Create different defines for ICACHE and ICCM enable combinations localparam NUM_OF_BEATS = 8 ; logic [31:3] ifu_ic_req_addr_f; logic uncacheable_miss_in ; logic uncacheable_miss_ff; logic bus_ifu_wr_en ; logic bus_ifu_wr_en_ff ; logic bus_ifu_wr_en_ff_q ; logic bus_ifu_wr_en_ff_wo_err ; logic [pt.ICACHE_NUM_WAYS-1:0] bus_ic_wr_en ; logic reset_tag_valid_for_miss ; logic [pt.ICACHE_STATUS_BITS-1:0] way_status; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_mb_in; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_rep_new; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_mb_ff; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_new; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_hit_new; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_new_w_debug; logic [pt.ICACHE_NUM_WAYS-1:0] tagv_mb_in; logic [pt.ICACHE_NUM_WAYS-1:0] tagv_mb_ff; logic ifu_wr_data_comb_err ; logic ifu_byp_data_err_new; logic [1:0] ifu_byp_data_err_f; logic ifu_wr_cumulative_err_data; logic ifu_wr_cumulative_err; logic ifu_wr_data_comb_err_ff; logic scnd_miss_index_match ; logic ifc_dma_access_q_ok; logic ifc_iccm_access_f ; logic ifc_region_acc_fault_f; logic ifc_region_acc_fault_final_f; logic [1:0] ifc_bus_acc_fault_f; logic ic_act_miss_f; logic ic_miss_under_miss_f; logic ic_ignore_2nd_miss_f; logic ic_act_hit_f; logic miss_pending; logic [31:1] imb_in , imb_ff ; logic [31:pt.ICACHE_BEAT_ADDR_HI+1] miss_addr_in , miss_addr ; logic miss_wrap_f ; logic flush_final_f; logic ifc_fetch_req_f; logic ifc_fetch_req_f_raw; logic fetch_req_f_qual ; logic ifc_fetch_req_qual_bf ; logic [pt.ICACHE_NUM_WAYS-1:0] replace_way_mb_any; logic last_beat; logic reset_beat_cnt ; logic [pt.ICACHE_BEAT_ADDR_HI:3] ic_req_addr_bits_hi_3 ; logic [pt.ICACHE_BEAT_ADDR_HI:3] ic_wr_addr_bits_hi_3 ; logic [31:1] ifu_fetch_addr_int_f ; logic [31:1] ifu_ic_rw_int_addr ; logic crit_wd_byp_ok_ff ; logic ic_crit_wd_rdy_new_ff; logic [79:0] ic_byp_data_only_pre_new; logic [79:0] ic_byp_data_only_new; logic ic_byp_hit_f ; logic ic_valid ; logic ic_valid_ff; logic reset_all_tags; logic ic_valid_w_debug; logic [pt.ICACHE_NUM_WAYS-1:0] ifu_tag_wren,ifu_tag_wren_ff; logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_tag_wr_en; logic [pt.ICACHE_NUM_WAYS-1:0] ifu_tag_wren_w_debug; logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way_ff; logic ic_debug_rd_en_ff ; logic fetch_bf_f_c1_clken ; logic fetch_bf_f_c1_clk; logic debug_c1_clken; logic debug_c1_clk; logic reset_ic_in ; logic reset_ic_ff ; logic [pt.ICACHE_BEAT_ADDR_HI:1] vaddr_f ; logic [31:1] ifu_status_wr_addr; logic sel_mb_addr ; logic sel_mb_addr_ff ; logic sel_mb_status_addr ; logic [63:0] ic_final_data; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_new_ff ; logic way_status_wr_en_ff ; logic [pt.ICACHE_TAG_DEPTH-1:0][pt.ICACHE_STATUS_BITS-1:0] way_status_out ; logic [1:0] ic_debug_way_enc; logic [pt.IFU_BUS_TAG-1:0] ifu_bus_rid_ff; logic fetch_req_icache_f; logic fetch_req_iccm_f; logic ic_iccm_hit_f; logic fetch_uncacheable_ff; logic way_status_wr_en; logic sel_byp_data; logic sel_ic_data; logic sel_iccm_data; logic ic_rd_parity_final_err; logic ic_act_miss_f_delayed; logic bus_ifu_wr_data_error; logic bus_ifu_wr_data_error_ff; logic way_status_wr_en_w_debug; logic ic_debug_tag_val_rd_out; logic ifu_pmu_ic_miss_in; logic ifu_pmu_ic_hit_in; logic ifu_pmu_bus_error_in; logic ifu_pmu_bus_trxn_in; logic ifu_pmu_bus_busy_in; logic ic_debug_ict_array_sel_in; logic ic_debug_ict_array_sel_ff; logic debug_data_clken; logic last_data_recieved_in ; logic last_data_recieved_ff ; logic ifu_bus_rvalid ; logic ifu_bus_rvalid_ff ; logic ifu_bus_rvalid_unq_ff ; logic ifu_bus_arready_unq ; logic ifu_bus_arready_unq_ff ; logic ifu_bus_arvalid ; logic ifu_bus_arvalid_ff ; logic ifu_bus_arready ; logic ifu_bus_arready_ff ; logic [63:0] ifu_bus_rdata_ff ; logic [1:0] ifu_bus_rresp_ff ; logic ifu_bus_rsp_valid ; logic ifu_bus_rsp_ready ; logic [pt.IFU_BUS_TAG-1:0] ifu_bus_rsp_tag; logic [63:0] ifu_bus_rsp_rdata; logic [1:0] ifu_bus_rsp_opc; logic [pt.ICACHE_NUM_BEATS-1:0] write_fill_data; logic [pt.ICACHE_NUM_BEATS-1:0] wr_data_c1_clk; logic [pt.ICACHE_NUM_BEATS-1:0] ic_miss_buff_data_valid_in; logic [pt.ICACHE_NUM_BEATS-1:0] ic_miss_buff_data_valid; logic [pt.ICACHE_NUM_BEATS-1:0] ic_miss_buff_data_error_in; logic [pt.ICACHE_NUM_BEATS-1:0] ic_miss_buff_data_error; logic [pt.ICACHE_BEAT_ADDR_HI:1] byp_fetch_index; logic [pt.ICACHE_BEAT_ADDR_HI:2] byp_fetch_index_0; logic [pt.ICACHE_BEAT_ADDR_HI:2] byp_fetch_index_1; logic [pt.ICACHE_BEAT_ADDR_HI:3] byp_fetch_index_inc; logic [pt.ICACHE_BEAT_ADDR_HI:2] byp_fetch_index_inc_0; logic [pt.ICACHE_BEAT_ADDR_HI:2] byp_fetch_index_inc_1; logic miss_buff_hit_unq_f ; logic stream_hit_f ; logic stream_miss_f ; logic stream_eol_f ; logic crit_byp_hit_f ; logic [pt.IFU_BUS_TAG-1:0] other_tag ; logic [(2*pt.ICACHE_NUM_BEATS)-1:0] [31:0] ic_miss_buff_data; logic [63:0] ic_miss_buff_half; logic scnd_miss_req, scnd_miss_req_q; logic scnd_miss_req_in; logic [pt.ICCM_BITS-1:2] iccm_ecc_corr_index_ff; logic [pt.ICCM_BITS-1:2] iccm_ecc_corr_index_in; logic [38:0] iccm_ecc_corr_data_ff; logic iccm_ecc_write_status ; logic iccm_rd_ecc_single_err_ff ; logic iccm_error_start; // start the error fsm logic perr_state_en; logic miss_state_en; logic busclk; logic busclk_force; logic busclk_reset; logic bus_ifu_bus_clk_en_ff; logic bus_ifu_bus_clk_en ; logic ifc_bus_ic_req_ff_in; logic ifu_bus_cmd_valid ; logic ifu_bus_cmd_ready ; logic bus_inc_data_beat_cnt ; logic bus_reset_data_beat_cnt ; logic bus_hold_data_beat_cnt ; logic bus_inc_cmd_beat_cnt ; logic bus_reset_cmd_beat_cnt_0 ; logic bus_reset_cmd_beat_cnt_secondlast ; logic bus_hold_cmd_beat_cnt ; logic [pt.ICACHE_BEAT_BITS-1:0] bus_new_data_beat_count ; logic [pt.ICACHE_BEAT_BITS-1:0] bus_data_beat_count ; logic [pt.ICACHE_BEAT_BITS-1:0] bus_new_cmd_beat_count ; logic [pt.ICACHE_BEAT_BITS-1:0] bus_cmd_beat_count ; logic [pt.ICACHE_BEAT_BITS-1:0] bus_new_rd_addr_count; logic [pt.ICACHE_BEAT_BITS-1:0] bus_rd_addr_count; logic bus_cmd_sent ; logic bus_last_data_beat ; logic [pt.ICACHE_NUM_WAYS-1:0] bus_wren ; logic [pt.ICACHE_NUM_WAYS-1:0] bus_wren_last ; logic [pt.ICACHE_NUM_WAYS-1:0] wren_reset_miss ; logic ifc_dma_access_ok_d; logic ifc_dma_access_ok_prev; logic bus_cmd_req_in ; logic bus_cmd_req_hold ; logic second_half_available ; logic write_ic_16_bytes ; logic ifc_region_acc_fault_final_bf; logic ifc_region_acc_fault_memory_bf; logic ifc_region_acc_fault_memory_f; logic ifc_region_acc_okay; logic iccm_correct_ecc; logic dma_sb_err_state, dma_sb_err_state_ff; logic two_byte_instr; typedef enum logic [2:0] {IDLE=3'b000, CRIT_BYP_OK=3'b001, HIT_U_MISS=3'b010, MISS_WAIT=3'b011,CRIT_WRD_RDY=3'b100,SCND_MISS=3'b101,STREAM=3'b110 , STALL_SCND_MISS=3'b111} miss_state_t; miss_state_t miss_state, miss_nxtstate; typedef enum logic [1:0] {ERR_STOP_IDLE=2'b00, ERR_FETCH1=2'b01 , ERR_FETCH2=2'b10 , ERR_STOP_FETCH=2'b11} err_stop_state_t; err_stop_state_t err_stop_state, err_stop_nxtstate; logic err_stop_state_en ; logic err_stop_fetch ; logic ic_crit_wd_rdy; // Critical fetch is ready to be bypassed. logic ifu_bp_hit_taken_q_f; logic ifu_bus_rvalid_unq; logic bus_cmd_beat_en; // ---- Clock gating section ----- // c1 clock enables assign fetch_bf_f_c1_clken = ifc_fetch_req_bf_raw | ifc_fetch_req_f | miss_pending | exu_flush_final | scnd_miss_req; assign debug_c1_clken = ic_debug_rd_en | ic_debug_wr_en ; // C1 - 1 clock pulse for data `ifdef RV_FPGA_OPTIMIZE assign fetch_bf_f_c1_clk = 1'b0; assign debug_c1_clk = 1'b0; `else rvclkhdr fetch_bf_f_c1_cgc ( .en(fetch_bf_f_c1_clken), .l1clk(fetch_bf_f_c1_clk), .* ); rvclkhdr debug_c1_cgc ( .en(debug_c1_clken), .l1clk(debug_c1_clk), .* ); `endif // ------ end clock gating section ------------------------ logic [1:0] iccm_single_ecc_error; logic dma_iccm_req_f ; assign iccm_dma_sb_error = (|iccm_single_ecc_error[1:0] ) & dma_iccm_req_f ; assign ifu_async_error_start = iccm_rd_ecc_single_err | ic_error_start; typedef enum logic [2:0] {ERR_IDLE=3'b000, IC_WFF=3'b001 , ECC_WFF=3'b010 , ECC_CORR=3'b011, DMA_SB_ERR=3'b100} perr_state_t; perr_state_t perr_state, perr_nxtstate; assign ic_dma_active = iccm_correct_ecc | (perr_state == DMA_SB_ERR) | (err_stop_state == ERR_STOP_FETCH) | err_stop_fetch | dec_tlu_flush_err_wb; // The last term is to give a error-correction a chance to finish before refetch starts assign scnd_miss_req_in = ifu_bus_rsp_valid & bus_ifu_bus_clk_en & ifu_bus_rsp_ready & (&bus_new_data_beat_count[pt.ICACHE_BEAT_BITS-1:0]) & ~uncacheable_miss_ff & ((miss_state == SCND_MISS) | (miss_nxtstate == SCND_MISS)) & ~exu_flush_final; assign ifu_bp_hit_taken_q_f = ifu_bp_hit_taken_f & ic_hit_f ; //////////////////////////////////// Create Miss State Machine /////////////////////// // Create Miss State Machine // // Create Miss State Machine // // Create Miss State Machine // //////////////////////////////////// Create Miss State Machine /////////////////////// // FIFO state machine always_comb begin : MISS_SM miss_nxtstate = IDLE; miss_state_en = 1'b0; case (miss_state) IDLE: begin : idle miss_nxtstate = (ic_act_miss_f & ~exu_flush_final) ? CRIT_BYP_OK : HIT_U_MISS ; miss_state_en = ic_act_miss_f & ~dec_tlu_force_halt ; end CRIT_BYP_OK: begin : crit_byp_ok miss_nxtstate = (dec_tlu_force_halt ) ? IDLE : ( ic_byp_hit_f & (last_data_recieved_ff | (bus_ifu_wr_en_ff & last_beat)) & uncacheable_miss_ff) ? IDLE : ( ic_byp_hit_f & ~last_data_recieved_ff & uncacheable_miss_ff) ? MISS_WAIT : (~ic_byp_hit_f & ~exu_flush_final & (bus_ifu_wr_en_ff & last_beat) & uncacheable_miss_ff) ? CRIT_WRD_RDY : ( (bus_ifu_wr_en_ff & last_beat) & ~uncacheable_miss_ff) ? IDLE : ( ic_byp_hit_f & ~exu_flush_final & ~(bus_ifu_wr_en_ff & last_beat) & ~ifu_bp_hit_taken_q_f & ~uncacheable_miss_ff) ? STREAM : ( bus_ifu_wr_en_ff & ~exu_flush_final & ~(bus_ifu_wr_en_ff & last_beat) & ~ifu_bp_hit_taken_q_f & ~uncacheable_miss_ff) ? STREAM : (~ic_byp_hit_f & ~exu_flush_final & (bus_ifu_wr_en_ff & last_beat) & ~uncacheable_miss_ff) ? IDLE : ( (exu_flush_final | ifu_bp_hit_taken_q_f) & ~(bus_ifu_wr_en_ff & last_beat) ) ? HIT_U_MISS : IDLE; miss_state_en = dec_tlu_force_halt | exu_flush_final | ic_byp_hit_f | ifu_bp_hit_taken_q_f | (bus_ifu_wr_en_ff & last_beat) | (bus_ifu_wr_en_ff & ~uncacheable_miss_ff) ; end CRIT_WRD_RDY: begin : crit_wrd_rdy miss_nxtstate = IDLE ; miss_state_en = exu_flush_final | flush_final_f | ic_byp_hit_f | dec_tlu_force_halt ; end STREAM: begin : stream miss_nxtstate = ((exu_flush_final | ifu_bp_hit_taken_q_f | stream_eol_f ) & ~(bus_ifu_wr_en_ff & last_beat) & ~dec_tlu_force_halt) ? HIT_U_MISS : IDLE ; miss_state_en = exu_flush_final | ifu_bp_hit_taken_q_f | stream_eol_f | (bus_ifu_wr_en_ff & last_beat) | dec_tlu_force_halt ; end MISS_WAIT: begin : miss_wait miss_nxtstate = (exu_flush_final & ~(bus_ifu_wr_en_ff & last_beat) & ~dec_tlu_force_halt) ? HIT_U_MISS : IDLE ; miss_state_en = exu_flush_final | (bus_ifu_wr_en_ff & last_beat) | dec_tlu_force_halt ; end HIT_U_MISS: begin : hit_u_miss miss_nxtstate = ic_miss_under_miss_f & ~(bus_ifu_wr_en_ff & last_beat) & ~dec_tlu_force_halt ? SCND_MISS : ic_ignore_2nd_miss_f & ~(bus_ifu_wr_en_ff & last_beat) & ~dec_tlu_force_halt ? STALL_SCND_MISS : IDLE ; miss_state_en = (bus_ifu_wr_en_ff & last_beat) | ic_miss_under_miss_f | ic_ignore_2nd_miss_f | dec_tlu_force_halt; end SCND_MISS: begin : scnd_miss miss_nxtstate = dec_tlu_force_halt ? IDLE : exu_flush_final ? ((bus_ifu_wr_en_ff & last_beat) ? IDLE : HIT_U_MISS) : CRIT_BYP_OK; miss_state_en = (bus_ifu_wr_en_ff & last_beat) | exu_flush_final | dec_tlu_force_halt; end STALL_SCND_MISS: begin : stall_scnd_miss miss_nxtstate = dec_tlu_force_halt ? IDLE : exu_flush_final ? ((bus_ifu_wr_en_ff & last_beat) ? IDLE : HIT_U_MISS) : IDLE; miss_state_en = (bus_ifu_wr_en_ff & last_beat) | exu_flush_final | dec_tlu_force_halt; end /*pragma coverage off*/ default: begin : def_case miss_nxtstate = IDLE; miss_state_en = 1'b0; end /*pragma coverage on*/ endcase end rvdffs #(($bits(miss_state_t))) miss_state_ff (.clk(active_clk), .din(miss_nxtstate), .dout({miss_state}), .en(miss_state_en), .*); logic sel_hold_imb ; assign miss_pending = (miss_state != IDLE) ; assign crit_wd_byp_ok_ff = (miss_state == CRIT_BYP_OK) | ((miss_state == CRIT_WRD_RDY) & ~flush_final_f); assign sel_hold_imb = (miss_pending & ~(bus_ifu_wr_en_ff & last_beat) & ~((miss_state == CRIT_WRD_RDY) & exu_flush_final) & ~((miss_state == CRIT_WRD_RDY) & crit_byp_hit_f) ) | ic_act_miss_f | (miss_pending & (miss_nxtstate == CRIT_WRD_RDY)) ; logic sel_hold_imb_scnd; logic [31:1] imb_scnd_in; logic [31:1] imb_scnd_ff; logic uncacheable_miss_scnd_in ; logic uncacheable_miss_scnd_ff ; logic [pt.ICACHE_NUM_WAYS-1:0] tagv_mb_scnd_in; logic [pt.ICACHE_NUM_WAYS-1:0] tagv_mb_scnd_ff; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_mb_scnd_in; logic [pt.ICACHE_STATUS_BITS-1:0] way_status_mb_scnd_ff; assign sel_hold_imb_scnd =((miss_state == SCND_MISS) | ic_miss_under_miss_f) & ~flush_final_f ; assign way_status_mb_scnd_in[pt.ICACHE_STATUS_BITS-1:0] = (miss_state == SCND_MISS) ? way_status_mb_scnd_ff[pt.ICACHE_STATUS_BITS-1:0] : {way_status[pt.ICACHE_STATUS_BITS-1:0]} ; assign tagv_mb_scnd_in[pt.ICACHE_NUM_WAYS-1:0] = (miss_state == SCND_MISS) ? tagv_mb_scnd_ff[pt.ICACHE_NUM_WAYS-1:0] : ({ic_tag_valid[pt.ICACHE_NUM_WAYS-1:0]} & {pt.ICACHE_NUM_WAYS{~reset_all_tags & ~exu_flush_final}}); assign uncacheable_miss_scnd_in = sel_hold_imb_scnd ? uncacheable_miss_scnd_ff : ifc_fetch_uncacheable_bf ; rvdff_fpga #(1) unc_miss_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din (uncacheable_miss_scnd_in), .dout(uncacheable_miss_scnd_ff)); rvdffpcie #(31) imb_f_scnd_ff (.*, .en(fetch_bf_f_c1_clken), .din ({imb_scnd_in[31:1]}), .dout({imb_scnd_ff[31:1]})); rvdff_fpga #(pt.ICACHE_STATUS_BITS) mb_rep_wayf2_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ({way_status_mb_scnd_in[pt.ICACHE_STATUS_BITS-1:0]}), .dout({way_status_mb_scnd_ff[pt.ICACHE_STATUS_BITS-1:0]})); rvdff_fpga #(pt.ICACHE_NUM_WAYS) mb_tagv_scnd_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ({tagv_mb_scnd_in[pt.ICACHE_NUM_WAYS-1:0]}), .dout({tagv_mb_scnd_ff[pt.ICACHE_NUM_WAYS-1:0]})); assign ic_req_addr_bits_hi_3[pt.ICACHE_BEAT_ADDR_HI:3] = bus_rd_addr_count[pt.ICACHE_BEAT_BITS-1:0] ; assign ic_wr_addr_bits_hi_3[pt.ICACHE_BEAT_ADDR_HI:3] = ifu_bus_rid_ff[pt.ICACHE_BEAT_BITS-1:0] & {pt.ICACHE_BEAT_BITS{bus_ifu_wr_en_ff}}; // NOTE: Cacheline size is 16 bytes in this example. // Tag Index Bank Offset // [31:16] [15:5] [4] [3:0] assign fetch_req_icache_f = ifc_fetch_req_f & ~ifc_iccm_access_f & ~ifc_region_acc_fault_final_f; assign fetch_req_iccm_f = ifc_fetch_req_f & ifc_iccm_access_f; assign ic_iccm_hit_f = fetch_req_iccm_f & (~miss_pending | (miss_state==HIT_U_MISS) | (miss_state==STREAM)); assign ic_byp_hit_f = (crit_byp_hit_f | stream_hit_f) & fetch_req_icache_f & miss_pending ; assign ic_act_hit_f = (|ic_rd_hit[pt.ICACHE_NUM_WAYS-1:0]) & fetch_req_icache_f & ~reset_all_tags & (~miss_pending | (miss_state==HIT_U_MISS)) & ~sel_mb_addr_ff; assign ic_act_miss_f = (((~(|ic_rd_hit[pt.ICACHE_NUM_WAYS-1:0]) | reset_all_tags) & fetch_req_icache_f & ~miss_pending) | scnd_miss_req) & ~ifc_region_acc_fault_final_f; assign ic_miss_under_miss_f = (~(|ic_rd_hit[pt.ICACHE_NUM_WAYS-1:0]) | reset_all_tags) & fetch_req_icache_f & (miss_state == HIT_U_MISS) & (imb_ff[31:pt.ICACHE_TAG_INDEX_LO] != ifu_fetch_addr_int_f[31:pt.ICACHE_TAG_INDEX_LO]) & ~uncacheable_miss_ff & ~sel_mb_addr_ff & ~ifc_region_acc_fault_final_f; assign ic_ignore_2nd_miss_f = (~(|ic_rd_hit[pt.ICACHE_NUM_WAYS-1:0]) | reset_all_tags) & fetch_req_icache_f & (miss_state == HIT_U_MISS) & ((imb_ff[31:pt.ICACHE_TAG_INDEX_LO] == ifu_fetch_addr_int_f[31:pt.ICACHE_TAG_INDEX_LO]) | uncacheable_miss_ff) ; assign ic_hit_f = ic_act_hit_f | ic_byp_hit_f | ic_iccm_hit_f | (ifc_region_acc_fault_final_f & ifc_fetch_req_f); assign uncacheable_miss_in = scnd_miss_req ? uncacheable_miss_scnd_ff : sel_hold_imb ? uncacheable_miss_ff : ifc_fetch_uncacheable_bf ; assign imb_in[31:1] = scnd_miss_req ? imb_scnd_ff[31:1] : sel_hold_imb ? imb_ff[31:1] : {ifc_fetch_addr_bf[31:1]} ; assign imb_scnd_in[31:1] = sel_hold_imb_scnd ? imb_scnd_ff[31:1] : {ifc_fetch_addr_bf[31:1]} ; assign scnd_miss_index_match = (imb_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO] == imb_scnd_ff[pt.ICACHE_INDEX_HI:pt.ICACHE_TAG_INDEX_LO]) & scnd_miss_req & ~ifu_wr_cumulative_err_data; assign way_status_mb_in[pt.ICACHE_STATUS_BITS-1:0] = (scnd_miss_req & ~scnd_miss_index_match) ? way_status_mb_scnd_ff[pt.ICACHE_STATUS_BITS-1:0] : (scnd_miss_req & scnd_miss_index_match) ? way_status_rep_new[pt.ICACHE_STATUS_BITS-1:0] : miss_pending ? way_status_mb_ff[pt.ICACHE_STATUS_BITS-1:0] : {way_status[pt.ICACHE_STATUS_BITS-1:0]} ; assign tagv_mb_in[pt.ICACHE_NUM_WAYS-1:0] = scnd_miss_req ? (tagv_mb_scnd_ff[pt.ICACHE_NUM_WAYS-1:0] | ({pt.ICACHE_NUM_WAYS {scnd_miss_index_match}} & replace_way_mb_any[pt.ICACHE_NUM_WAYS-1:0])) : miss_pending ? tagv_mb_ff[pt.ICACHE_NUM_WAYS-1:0] : ({ic_tag_valid[pt.ICACHE_NUM_WAYS-1:0]} & {pt.ICACHE_NUM_WAYS{~reset_all_tags & ~exu_flush_final}}) ; assign reset_ic_in = miss_pending & ~scnd_miss_req_q & (reset_all_tags | reset_ic_ff) ; rvdffpcie #(31) ifu_fetch_addr_f_ff (.*, .en(fetch_bf_f_c1_clken), .din ({ifc_fetch_addr_bf[31:1]}), .dout({ifu_fetch_addr_int_f[31:1]})); assign vaddr_f[pt.ICACHE_BEAT_ADDR_HI:1] = ifu_fetch_addr_int_f[pt.ICACHE_BEAT_ADDR_HI:1] ; rvdffpcie #(31) imb_f_ff (.*, .en(fetch_bf_f_c1_clken), .din (imb_in[31:1]), .dout(imb_ff[31:1])); rvdff_fpga #(1) unc_miss_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ( uncacheable_miss_in), .dout( uncacheable_miss_ff)); assign miss_addr_in[31:pt.ICACHE_BEAT_ADDR_HI+1] = (~miss_pending ) ? imb_ff[31:pt.ICACHE_BEAT_ADDR_HI+1] : ( scnd_miss_req_q ) ? imb_scnd_ff[31:pt.ICACHE_BEAT_ADDR_HI+1] : miss_addr[31:pt.ICACHE_BEAT_ADDR_HI+1] ; rvdfflie #(.WIDTH(31-pt.ICACHE_BEAT_ADDR_HI),.LEFT(31-pt.ICACHE_BEAT_ADDR_HI-8)) miss_f_ff (.*, .en(bus_ifu_bus_clk_en | ic_act_miss_f | dec_tlu_force_halt), .din ({miss_addr_in[31:pt.ICACHE_BEAT_ADDR_HI+1]}), .dout({miss_addr[31:pt.ICACHE_BEAT_ADDR_HI+1]})); rvdff_fpga #(pt.ICACHE_STATUS_BITS) mb_rep_wayf2_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ({way_status_mb_in[pt.ICACHE_STATUS_BITS-1:0]}), .dout({way_status_mb_ff[pt.ICACHE_STATUS_BITS-1:0]})); rvdff_fpga #(pt.ICACHE_NUM_WAYS) mb_tagv_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din ({tagv_mb_in[pt.ICACHE_NUM_WAYS-1:0]}), .dout({tagv_mb_ff[pt.ICACHE_NUM_WAYS-1:0]})); assign ifc_fetch_req_qual_bf = ifc_fetch_req_bf & ~((miss_state == CRIT_WRD_RDY) & flush_final_f) & ~stream_miss_f ;// & ~exu_flush_final ; assign ifc_fetch_req_f = ifc_fetch_req_f_raw & ~exu_flush_final ; rvdff_fpga #(1) ifu_iccm_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din(ifc_iccm_access_bf), .dout(ifc_iccm_access_f)); rvdff_fpga #(1) ifu_iccm_reg_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din(ifc_region_acc_fault_final_bf), .dout(ifc_region_acc_fault_final_f)); rvdff_fpga #(1) rgn_acc_ff (.*, .clk(fetch_bf_f_c1_clk), .clken(fetch_bf_f_c1_clken), .rawclk(clk), .din(ifc_region_acc_fault_bf), .dout(ifc_region_acc_fault_f)); assign ifu_ic_req_addr_f[31:3] = {miss_addr[31:pt.ICACHE_BEAT_ADDR_HI+1] , ic_req_addr_bits_hi_3[pt.ICACHE_BEAT_ADDR_HI:3] }; assign ifu_ic_mb_empty = (((miss_state == HIT_U_MISS) | (miss_state == STREAM)) & ~(bus_ifu_wr_en_ff & last_beat)) | ~miss_pending ; assign ifu_miss_state_idle = (miss_state == IDLE) ; assign sel_mb_addr = ((miss_pending & write_ic_16_bytes & ~uncacheable_miss_ff) | reset_tag_valid_for_miss) ; assign ifu_ic_rw_int_addr[31:1] = ({31{ sel_mb_addr}} & {imb_ff[31:pt.ICACHE_BEAT_ADDR_HI+1] , ic_wr_addr_bits_hi_3[pt.ICACHE_BEAT_ADDR_HI:3] , imb_ff[2:1]}) | ({31{~sel_mb_addr}} & ifc_fetch_addr_bf[31:1] ) ; assign sel_mb_status_addr = ((miss_pending & write_ic_16_bytes & ~uncacheable_miss_ff & last_beat & bus_ifu_wr_en_ff_q) | reset_tag_valid_for_miss) ; assign ifu_status_wr_addr[31:1] = ({31{ sel_mb_status_addr}} & {imb_ff[31:pt.ICACHE_BEAT_ADDR_HI+1] , ic_wr_addr_bits_hi_3[pt.ICACHE_BEAT_ADDR_HI:3] , imb_ff[2:1]}) | ({31{~sel_mb_status_addr}} & ifu_fetch_addr_int_f[31:1] ) ; assign ic_rw_addr[31:1] = ifu_ic_rw_int_addr[31:1] ; if (pt.ICACHE_ECC == 1) begin: icache_ecc_1 logic [6:0] ic_wr_ecc; logic [6:0] ic_miss_buff_ecc; logic [141:0] ic_wr_16bytes_data ; logic [70:0] ifu_ic_debug_rd_data_in ; rvecc_encode_64 ic_ecc_encode_64_bus ( .din (ifu_bus_rdata_ff[63:0]), .ecc_out(ic_wr_ecc[6:0])); rvecc_encode_64 ic_ecc_encode_64_buff ( .din (ic_miss_buff_half[63:0]), .ecc_out(ic_miss_buff_ecc[6:0])); for (genvar i=0; i < pt.ICACHE_BANKS_WAY ; i++) begin : ic_wr_data_loop assign ic_wr_data[i][70:0] = ic_wr_16bytes_data[((71*i)+70): (71*i)]; end assign ic_debug_wr_data[70:0] = {dec_tlu_ic_diag_pkt.icache_wrdata[70:0]} ; assign ic_error_start = ((|ic_eccerr[pt.ICACHE_BANKS_WAY-1:0]) & ic_act_hit_f) | ic_rd_parity_final_err; assign ifu_ic_debug_rd_data_in[70:0] = ic_debug_ict_array_sel_ff ? {2'b0,ictag_debug_rd_data[25:21],32'b0,ictag_debug_rd_data[20:0],{7-pt.ICACHE_STATUS_BITS{1'b0}}, way_status[pt.ICACHE_STATUS_BITS-1:0],3'b0,ic_debug_tag_val_rd_out} : ic_debug_rd_data[70:0]; rvdffe #(71) ifu_debug_data_ff (.*, .en (debug_data_clken), .din ({ ifu_ic_debug_rd_data_in[70:0] }), .dout({ ifu_ic_debug_rd_data[70:0] }) ); assign ic_wr_16bytes_data[141:0] = ifu_bus_rid_ff[0] ? {ic_wr_ecc[6:0] , ifu_bus_rdata_ff[63:0] , ic_miss_buff_ecc[6:0] , ic_miss_buff_half[63:0] } : {ic_miss_buff_ecc[6:0] , ic_miss_buff_half[63:0] , ic_wr_ecc[6:0] , ifu_bus_rdata_ff[63:0] } ; end else begin : icache_parity_1 logic [3:0] ic_wr_parity; logic [3:0] ic_miss_buff_parity; logic [135:0] ic_wr_16bytes_data ; logic [70:0] ifu_ic_debug_rd_data_in ; for (genvar i=0 ; i < 4 ; i++) begin : DATA_PGEN rveven_paritygen #(16) par_bus (.data_in (ifu_bus_rdata_ff[((16*i)+15):(16*i)]), .parity_out(ic_wr_parity[i])); rveven_paritygen #(16) par_buff (.data_in (ic_miss_buff_half[((16*i)+15):(16*i)]), .parity_out(ic_miss_buff_parity[i])); end for (genvar i=0; i < pt.ICACHE_BANKS_WAY ; i++) begin : ic_wr_data_loop assign ic_wr_data[i][70:0] = {3'b0, ic_wr_16bytes_data[((68*i)+67): (68*i)]}; end assign ic_debug_wr_data[70:0] = {dec_tlu_ic_diag_pkt.icache_wrdata[70:0]} ; assign ic_error_start = ((|ic_parerr[pt.ICACHE_BANKS_WAY-1:0]) & ic_act_hit_f) | ic_rd_parity_final_err; assign ifu_ic_debug_rd_data_in[70:0] = ic_debug_ict_array_sel_ff ? {6'b0,ictag_debug_rd_data[21],32'b0,ictag_debug_rd_data[20:0],{7-pt.ICACHE_STATUS_BITS{1'b0}},way_status[pt.ICACHE_STATUS_BITS-1:0],3'b0,ic_debug_tag_val_rd_out} : ic_debug_rd_data[70:0] ; rvdffe #(71) ifu_debug_data_ff (.*, .en (debug_data_clken), .din ({ ifu_ic_debug_rd_data_in[70:0] }), .dout({ ifu_ic_debug_rd_data[70:0] }) ); assign ic_wr_16bytes_data[135:0] = ifu_bus_rid_ff[0] ? {ic_wr_parity[3:0] , ifu_bus_rdata_ff[63:0] , ic_miss_buff_parity[3:0] , ic_miss_buff_half[63:0] } : {ic_miss_buff_parity[3:0] , ic_miss_buff_half[63:0] , ic_wr_parity[3:0] , ifu_bus_rdata_ff[63:0] } ; end assign ifu_wr_data_comb_err = bus_ifu_wr_data_error_ff ; assign ifu_wr_cumulative_err = (ifu_wr_data_comb_err | ifu_wr_data_comb_err_ff) & ~reset_beat_cnt; assign ifu_wr_cumulative_err_data = ifu_wr_data_comb_err | ifu_wr_data_comb_err_ff ; assign sel_byp_data = (ic_crit_wd_rdy | (miss_state == STREAM) | (miss_state == CRIT_BYP_OK)); assign sel_ic_data = ~(ic_crit_wd_rdy | (miss_state == STREAM) | (miss_state == CRIT_BYP_OK) | (miss_state == MISS_WAIT)) & ~fetch_req_iccm_f & ~ifc_region_acc_fault_final_f; if (pt.ICCM_ICACHE==1) begin: iccm_icache assign sel_iccm_data = fetch_req_iccm_f ; assign ic_final_data[63:0] = ({64{sel_byp_data | sel_iccm_data | sel_ic_data}} & {ic_rd_data[63:0]} ) ; assign ic_premux_data[63:0] = ({64{sel_byp_data }} & {ic_byp_data_only_new[63:0]} ) | ({64{sel_iccm_data}} & {iccm_rd_data[63:0]}); assign ic_sel_premux_data = sel_iccm_data | sel_byp_data ; end if (pt.ICCM_ONLY == 1 ) begin: iccm_only assign sel_iccm_data = fetch_req_iccm_f ; assign ic_final_data[63:0] = ({64{sel_byp_data }} & {ic_byp_data_only_new[63:0]} ) | ({64{sel_iccm_data}} & {iccm_rd_data[63:0]}); assign ic_premux_data = '0 ; assign ic_sel_premux_data = '0 ; end if (pt.ICACHE_ONLY == 1 ) begin: icache_only assign ic_final_data[63:0] = ({64{sel_byp_data | sel_ic_data}} & {ic_rd_data[63:0]} ) ; assign ic_premux_data[63:0] = ({64{sel_byp_data }} & {ic_byp_data_only_new[63:0]} ) ; assign ic_sel_premux_data = sel_byp_data ; end if (pt.NO_ICCM_NO_ICACHE == 1 ) begin: no_iccm_no_icache assign ic_final_data[63:0] = ({64{sel_byp_data }} & {ic_byp_data_only_new[63:0]} ) ; assign ic_premux_data = 0 ; assign ic_sel_premux_data = '0 ; end assign ifc_bus_acc_fault_f[1:0] = {2{ic_byp_hit_f}} & ifu_byp_data_err_f[1:0] ; assign ic_data_f[31:0] = ic_final_data[31:0]; assign fetch_req_f_qual = ic_hit_f & ~exu_flush_final; assign ic_access_fault_f[1:0] = ({2{ifc_region_acc_fault_final_f}} | ifc_bus_acc_fault_f[1:0]) & {2{~exu_flush_final}}; assign ic_access_fault_type_f[1:0] = |iccm_rd_ecc_double_err ? 2'b01 : ifc_region_acc_fault_f ? 2'b10 : ifc_region_acc_fault_memory_f ? 2'b11 : 2'b00 ; // right justified assign ic_fetch_val_f[1] = fetch_req_f_qual & ifu_bp_inst_mask_f & ~(vaddr_f[pt.ICACHE_BEAT_ADDR_HI:1] == {pt.ICACHE_BEAT_ADDR_HI{1'b1}}) & (err_stop_state != ERR_FETCH2); assign ic_fetch_val_f[0] = fetch_req_f_qual ; assign two_byte_instr = (ic_data_f[1:0] != 2'b11 ) ; ///////////////////////////////////////////////////////////////////////////////////// // Create full buffer... // ///////////////////////////////////////////////////////////////////////////////////// logic [63:0] ic_miss_buff_data_in; assign ic_miss_buff_data_in[63:0] = ifu_bus_rsp_rdata[63:0]; for (genvar i=0; i=1 & clk_count<=3) rst_l <= 1'b0; else rst_l <= 1'b1; if (clk_count > 3) begin compressed_din[15:0] <= compressed[clk_count-3]; // c.mv expected_val[31:0] <= expected[clk_count-3]; end if (clk_count == 65000) begin $dumpoff; $finish; end end // always @ (posedge clk) always @(negedge clk) begin if (clk_count > 3 & error) begin $display("clock: %d compressed %h error actual %h expected %h",clk_count,compressed_din,actual,expected_val); end end el2_ifu_compress_ctl align (.*,.din(compressed_din[15:0]),.dout(actual[31:0])); assign error = actual[31:0] != expected_val[31:0]; endmodule // el2_ifu_tb_memread ================================================ FILE: design/include/el2_dec_csr_equ_m.svh ================================================ logic csr_misa; logic csr_mvendorid; logic csr_marchid; logic csr_mimpid; logic csr_mhartid; logic csr_mstatus; logic csr_mtvec; logic csr_mip; logic csr_mie; logic csr_mcyclel; logic csr_mcycleh; logic csr_minstretl; logic csr_minstreth; logic csr_mscratch; logic csr_mepc; logic csr_mcause; logic csr_mscause; logic csr_mtval; logic csr_mrac; logic csr_dmst; logic csr_mdseac; logic csr_meihap; logic csr_meivt; logic csr_meipt; logic csr_meicurpl; logic csr_meicidpl; logic csr_dcsr; logic csr_mcgc; logic csr_mfdc; logic csr_dpc; logic csr_mtsel; logic csr_mtdata1; logic csr_mtdata2; logic csr_mhpmc3; logic csr_mhpmc4; logic csr_mhpmc5; logic csr_mhpmc6; logic csr_mhpmc3h; logic csr_mhpmc4h; logic csr_mhpmc5h; logic csr_mhpmc6h; logic csr_mhpme3; logic csr_mhpme4; logic csr_mhpme5; logic csr_mhpme6; logic csr_mcountinhibit; logic csr_mitctl0; logic csr_mitctl1; logic csr_mitb0; logic csr_mitb1; logic csr_mitcnt0; logic csr_mitcnt1; /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ logic csr_perfva; logic csr_perfvb; logic csr_perfvc; logic csr_perfvd; logic csr_perfve; logic csr_perfvf; logic csr_perfvg; logic csr_perfvh; logic csr_perfvi; /*pragma coverage on*/ logic csr_mpmc; logic csr_mcpc; logic csr_meicpct; logic csr_mdeau; logic csr_micect; logic csr_miccmect; logic csr_mdccmect; logic csr_mfdht; logic csr_mfdhs; logic csr_dicawics; logic csr_dicad0h; logic csr_dicad0; logic csr_dicad1; logic csr_dicago; logic csr_pmpcfg; logic csr_pmpaddr0; logic csr_pmpaddr16; logic csr_pmpaddr32; logic csr_pmpaddr48; logic valid_only; logic presync; logic postsync; assign csr_misa = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]); assign csr_mvendorid = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_marchid = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mimpid = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_mhartid = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[2]); assign csr_mstatus = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]); assign csr_mtvec = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]); assign csr_mip = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[2]); assign csr_mie = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]); assign csr_mcyclel = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]); assign csr_mcycleh = (dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_minstretl = (!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_minstreth = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mscratch = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mepc = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_mcause = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mscause = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[2]); assign csr_mtval = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_mrac = (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]); assign csr_dmst = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_mdseac = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]); assign csr_meihap = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[3]); assign csr_meivt = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_meipt = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_meicurpl = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[2]); assign csr_meicidpl = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_dcsr = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[0]); assign csr_mcgc = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[0]); assign csr_mfdc = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_dpc = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[0]); assign csr_mtsel = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mtdata1 = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[0]); assign csr_mtdata2 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[1]); assign csr_mhpmc3 = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[0]); assign csr_mhpmc4 = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpmc5 = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_mhpmc6 = (!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpmc3h = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[0]); assign csr_mhpmc4h = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpmc5h = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_mhpmc6h = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpme3 = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[0]); assign csr_mhpme4 = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpme5 = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_mhpme6 = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[1] &!dec_csr_rdaddr_d[0]); assign csr_mcountinhibit = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[0]); assign csr_mitctl0 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1] &!dec_csr_rdaddr_d[0]); assign csr_mitctl1 = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_mitb0 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_mitb1 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mitcnt0 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[0]); assign csr_mitcnt1 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_perfva = 1'b0; assign csr_perfvb = 1'b0; assign csr_perfvc = 1'b0; assign csr_perfvd = 1'b0; assign csr_perfve = 1'b0; assign csr_perfvf = 1'b0; assign csr_perfvg = 1'b0; assign csr_perfvh = 1'b0; assign csr_perfvi = 1'b0; assign csr_mpmc = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]); assign csr_mcpc = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]); assign csr_meicpct = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mdeau = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[3]); assign csr_micect = (dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_miccmect = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[0]); assign csr_mdccmect = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mfdht = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mfdhs = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]); assign csr_dicawics = (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_dicad0h = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_dicad0 = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_dicad1 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_dicago = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_pmpcfg = (!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]); assign csr_pmpaddr0 = (!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]); assign csr_pmpaddr16 = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]); assign csr_pmpaddr32 = (!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[4]); assign csr_pmpaddr48 = (dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]); assign valid_only = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]) | ( !dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[4]) | ( !dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[3]) | ( !dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[3]); assign presync = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[0]) | ( dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]) | (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign postsync = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]) | ( dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); logic legal; assign legal = (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1] &!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]) | (dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]) | ( !dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1] &!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]) | ( dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | ( dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[1]) | (dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]) | ( !dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[3]) | (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[3]) | (!dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]) | ( dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]); ================================================ FILE: design/include/el2_dec_csr_equ_mu.svh ================================================ logic csr_misa; logic csr_mvendorid; logic csr_marchid; logic csr_mimpid; logic csr_mhartid; logic csr_mstatus; logic csr_mtvec; logic csr_mip; logic csr_mie; logic csr_mcyclel; logic csr_mcycleh; logic csr_minstretl; logic csr_minstreth; logic csr_mscratch; logic csr_mepc; logic csr_mcause; logic csr_mscause; logic csr_mtval; logic csr_mrac; logic csr_dmst; logic csr_mdseac; logic csr_meihap; logic csr_meivt; logic csr_meipt; logic csr_meicurpl; logic csr_meicidpl; logic csr_dcsr; logic csr_mcgc; logic csr_mfdc; logic csr_dpc; logic csr_mtsel; logic csr_mtdata1; logic csr_mtdata2; logic csr_mhpmc3; logic csr_mhpmc4; logic csr_mhpmc5; logic csr_mhpmc6; logic csr_mhpmc3h; logic csr_mhpmc4h; logic csr_mhpmc5h; logic csr_mhpmc6h; logic csr_mhpme3; logic csr_mhpme4; logic csr_mhpme5; logic csr_mhpme6; logic csr_mcounteren; logic csr_mcountinhibit; logic csr_mitctl0; logic csr_mitctl1; logic csr_mitb0; logic csr_mitb1; logic csr_mitcnt0; logic csr_mitcnt1; /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ logic csr_perfva; logic csr_perfvb; logic csr_perfvc; logic csr_perfvd; logic csr_perfve; logic csr_perfvf; logic csr_perfvg; logic csr_perfvh; logic csr_perfvi; /*pragma coverage on*/ logic csr_mpmc; logic csr_mcpc; logic csr_meicpct; logic csr_mdeau; logic csr_micect; logic csr_miccmect; logic csr_mdccmect; logic csr_mfdht; logic csr_mfdhs; logic csr_dicawics; logic csr_dicad0h; logic csr_dicad0; logic csr_dicad1; logic csr_dicago; logic csr_menvcfg; logic csr_menvcfgh; logic csr_pmpcfg; logic csr_pmpaddr0; logic csr_pmpaddr16; logic csr_pmpaddr32; logic csr_pmpaddr48; logic csr_cyclel; logic csr_cycleh; logic csr_instretl; logic csr_instreth; logic csr_hpmc3; logic csr_hpmc4; logic csr_hpmc5; logic csr_hpmc6; logic csr_hpmc3h; logic csr_hpmc4h; logic csr_hpmc5h; logic csr_hpmc6h; logic csr_mseccfgl; logic csr_mseccfgh; logic valid_only; logic presync; logic postsync; assign csr_misa = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]); assign csr_mvendorid = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_marchid = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mimpid = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_mhartid = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[2]); assign csr_mstatus = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1] &!dec_csr_rdaddr_d[0]); assign csr_mtvec = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]); assign csr_mip = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[0]); assign csr_mie = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mcyclel = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_mcycleh = (!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_minstretl = (dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_minstreth = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mscratch = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mepc = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_mcause = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mscause = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[2]); assign csr_mtval = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_mrac = (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]); assign csr_dmst = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_mdseac = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[3]); assign csr_meihap = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[3]); assign csr_meivt = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_meipt = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_meicurpl = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[2]); assign csr_meicidpl = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_dcsr = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[0]); assign csr_mcgc = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[0]); assign csr_mfdc = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_dpc = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[0]); assign csr_mtsel = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mtdata1 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[0]); assign csr_mtdata2 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[1]); assign csr_mhpmc3 = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]); assign csr_mhpmc4 = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpmc5 = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_mhpmc6 = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpmc3h = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]); assign csr_mhpmc4h = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpmc5h = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_mhpmc6h = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpme3 = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[0]); assign csr_mhpme4 = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mhpme5 = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_mhpme6 = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[1] &!dec_csr_rdaddr_d[0]); assign csr_mcounteren = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]); assign csr_mcountinhibit = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[0]); assign csr_mitctl0 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1] &!dec_csr_rdaddr_d[0]); assign csr_mitctl1 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); assign csr_mitb0 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_mitb1 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mitcnt0 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[0]); assign csr_mitcnt1 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_perfva = 1'b0; assign csr_perfvb = 1'b0; assign csr_perfvc = 1'b0; assign csr_perfvd = 1'b0; assign csr_perfve = 1'b0; assign csr_perfvf = 1'b0; assign csr_perfvg = 1'b0; assign csr_perfvh = 1'b0; assign csr_perfvi = 1'b0; assign csr_mpmc = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]); assign csr_mcpc = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]); assign csr_meicpct = (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mdeau = (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[3]); assign csr_micect = (dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_miccmect = (dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[0]); assign csr_mdccmect = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mfdht = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_mfdhs = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[0]); assign csr_dicawics = (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_dicad0h = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_dicad0 = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_dicad1 = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_dicago = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_menvcfg = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3]); assign csr_menvcfgh = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]); assign csr_pmpcfg = (!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]); assign csr_pmpaddr0 = (!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]); assign csr_pmpaddr16 = (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]); assign csr_pmpaddr32 = (!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[4]); assign csr_pmpaddr48 = (dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]); assign csr_cyclel = (!dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_cycleh = (!dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]); assign csr_instretl = (!dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_instreth = (!dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_hpmc3 = (!dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_hpmc4 = (!dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_hpmc5 = (!dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_hpmc6 = (!dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]); assign csr_hpmc3h = (!dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_hpmc4h = (!dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]); assign csr_hpmc5h = (!dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]); assign csr_hpmc6h = (!dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]); assign csr_mseccfgl = (dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[4]); assign csr_mseccfgh = (!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[4]); assign valid_only = (!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]) | (!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[3]) | (dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[3]) | (dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]); assign presync = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[0]) | ( dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]) | (dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]) | ( dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]); assign postsync = (dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]) | ( dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]) | ( !dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]); logic legal; assign legal = (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1] &!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]) | (dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2]) | (!dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]) | ( dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[9] &!dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[10] &!dec_csr_rdaddr_d[9]&!dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]) | (dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[10]&!dec_csr_rdaddr_d[9]&!dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]) | ( !dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]) | ( !dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[1]) | ( dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2] &dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]) | (dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3] &dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[1]&dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]) | (dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1]) | ( !dec_csr_rdaddr_d[11]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[2] &!dec_csr_rdaddr_d[1]&!dec_csr_rdaddr_d[0]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[3]&dec_csr_rdaddr_d[2]&dec_csr_rdaddr_d[1] &dec_csr_rdaddr_d[0]) | (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[2]) | (!dec_csr_rdaddr_d[11] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[7] &!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&!dec_csr_rdaddr_d[4] &!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]&!dec_csr_rdaddr_d[0]) | ( !dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &!dec_csr_rdaddr_d[4]&!dec_csr_rdaddr_d[3]&!dec_csr_rdaddr_d[2]) | ( dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[1]) | (!dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[3]) | (!dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &!dec_csr_rdaddr_d[6]&dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]) | ( dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9] &dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5] &dec_csr_rdaddr_d[3]) | (dec_csr_rdaddr_d[11]&!dec_csr_rdaddr_d[10] &dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8]&!dec_csr_rdaddr_d[6] &!dec_csr_rdaddr_d[5]&dec_csr_rdaddr_d[4]) | (!dec_csr_rdaddr_d[11] &!dec_csr_rdaddr_d[10]&dec_csr_rdaddr_d[9]&dec_csr_rdaddr_d[8] &dec_csr_rdaddr_d[7]&dec_csr_rdaddr_d[6]&!dec_csr_rdaddr_d[5]); ================================================ FILE: design/include/el2_def.sv ================================================ // performance monitor stuff //`ifndef EL2_DEF_SV //`define EL2_DEF_SV package el2_pkg; `include "el2_pdef.vh" typedef struct packed { logic trace_rv_i_valid_ip; logic [31:0] trace_rv_i_insn_ip; logic [31:0] trace_rv_i_address_ip; logic trace_rv_i_exception_ip; logic [4:0] trace_rv_i_ecause_ip; logic trace_rv_i_interrupt_ip; logic [31:0] trace_rv_i_tval_ip; } el2_trace_pkt_t; typedef enum logic [3:0] { NULL_OP = 4'b0000, MUL = 4'b0001, LOAD = 4'b0010, STORE = 4'b0011, ALU = 4'b0100, CSRREAD = 4'b0101, CSRWRITE = 4'b0110, CSRRW = 4'b0111, EBREAK = 4'b1000, ECALL = 4'b1001, FENCE = 4'b1010, FENCEI = 4'b1011, MRET = 4'b1100, CONDBR = 4'b1101, JAL = 4'b1110, BITMANIPU = 4'b1111 } el2_inst_pkt_t; typedef struct packed { logic valid; logic wb; logic [2:0] tag; logic [4:0] rd; } el2_load_cam_pkt_t; typedef struct packed { logic pc0_call; logic pc0_ret; logic pc0_pc4; } el2_rets_pkt_t; typedef struct packed { logic valid; logic [11:0] toffset; logic [1:0] hist; logic br_error; logic br_start_error; logic bank; logic [31:1] prett; // predicted ret target logic way; logic ret; } el2_br_pkt_t; typedef struct packed { logic valid; logic [1:0] hist; logic br_error; logic br_start_error; logic way; logic middle; } el2_br_tlu_pkt_t; typedef struct packed { logic misp; logic ataken; logic boffset; logic pc4; logic [1:0] hist; logic [11:0] toffset; logic valid; logic br_error; logic br_start_error; logic pcall; logic pja; logic way; logic pret; // for power use the pret bit to clock the prett field logic [31:1] prett; } el2_predict_pkt_t; typedef struct packed { // unlikely to change logic icaf; logic icaf_second; logic [1:0] icaf_type; logic fence_i; logic [3:0] i0trigger; logic pmu_i0_br_unpred; // pmu logic pmu_divide; // likely to change logic legal; logic pmu_lsu_misaligned; el2_inst_pkt_t pmu_i0_itype; // pmu - instruction type } el2_trap_pkt_t; typedef struct packed { // unlikely to change logic i0div; logic csrwen; logic csrwonly; logic [11:0] csraddr; // likely to change logic [4:0] i0rd; logic i0load; logic i0store; logic i0v; logic i0valid; } el2_dest_pkt_t; typedef struct packed { logic mul; logic load; logic alu; } el2_class_pkt_t; typedef struct packed { logic [4:0] rs1; logic [4:0] rs2; logic [4:0] rd; } el2_reg_pkt_t; typedef struct packed { logic clz; logic ctz; logic cpop; logic sext_b; logic sext_h; logic min; logic max; logic pack; logic packu; logic packh; logic rol; logic ror; logic grev; logic gorc; logic zbb; logic bset; logic bclr; logic binv; logic bext; logic sh1add; logic sh2add; logic sh3add; logic zba; logic land; logic lor; logic lxor; logic sll; logic srl; logic sra; logic beq; logic bne; logic blt; logic bge; logic add; logic sub; logic slt; logic unsign; logic jal; logic predict_t; logic predict_nt; logic csr_write; logic csr_imm; } el2_alu_pkt_t; typedef struct packed { logic fast_int; /* verilator lint_off SYMRSVDWORD */ logic stack; /* verilator lint_on SYMRSVDWORD */ logic by; logic half; logic word; logic dword; // for dma logic load; logic store; logic unsign; logic dma; // dma pkt logic store_data_bypass_d; logic load_ldst_bypass_d; logic store_data_bypass_m; logic valid; } el2_lsu_pkt_t; typedef struct packed { logic inst_type; //0: Load, 1: Store //logic dma_valid; logic exc_type; //0: MisAligned, 1: Access Fault logic [3:0] mscause; logic [31:0] addr; logic single_ecc_error; logic exc_valid; } el2_lsu_error_pkt_t; typedef struct packed { logic clz; logic ctz; logic cpop; logic sext_b; logic sext_h; logic min; logic max; logic pack; logic packu; logic packh; logic rol; logic ror; logic grev; logic gorc; logic zbb; logic bset; logic bclr; logic binv; logic bext; logic zbs; logic bcompress; logic bdecompress; logic zbe; logic clmul; logic clmulh; logic clmulr; logic zbc; logic shfl; logic unshfl; logic xperm_n; logic xperm_b; logic xperm_h; logic zbp; logic crc32_b; logic crc32_h; logic crc32_w; logic crc32c_b; logic crc32c_h; logic crc32c_w; logic zbr; logic bfp; logic zbf; logic sh1add; logic sh2add; logic sh3add; logic zba; logic alu; logic rs1; logic rs2; logic imm12; logic rd; logic shimm5; logic imm20; logic pc; logic load; logic store; logic lsu; logic add; logic sub; logic land; logic lor; logic lxor; logic sll; logic sra; logic srl; logic slt; logic unsign; logic condbr; logic beq; logic bne; logic bge; logic blt; logic jal; logic by; logic half; logic word; logic csr_read; logic csr_clr; logic csr_set; logic csr_write; logic csr_imm; logic presync; logic postsync; logic ebreak; logic ecall; logic mret; logic mul; logic rs1_sign; logic rs2_sign; logic low; logic div; logic rem; logic fence; logic fence_i; logic pm_alu; logic legal; } el2_dec_pkt_t; typedef struct packed { logic valid; logic rs1_sign; logic rs2_sign; logic low; logic bcompress; logic bdecompress; logic clmul; logic clmulh; logic clmulr; logic grev; logic gorc; logic shfl; logic unshfl; logic crc32_b; logic crc32_h; logic crc32_w; logic crc32c_b; logic crc32c_h; logic crc32c_w; logic bfp; logic xperm_n; logic xperm_b; logic xperm_h; } el2_mul_pkt_t; typedef struct packed { logic valid; logic unsign; logic rem; } el2_div_pkt_t; typedef struct packed { logic TEST1; logic RME; logic [3:0] RM; logic LS; logic DS; logic SD; logic TEST_RNM; logic BC1; logic BC2; } el2_ccm_ext_in_pkt_t; typedef struct packed { logic TEST1; logic RME; logic [3:0] RM; logic LS; logic DS; logic SD; logic TEST_RNM; logic BC1; logic BC2; } el2_dccm_ext_in_pkt_t; typedef struct packed { logic TEST1; logic RME; logic [3:0] RM; logic LS; logic DS; logic SD; logic TEST_RNM; logic BC1; logic BC2; } el2_ic_data_ext_in_pkt_t; typedef struct packed { logic TEST1; logic RME; logic [3:0] RM; logic LS; logic DS; logic SD; logic TEST_RNM; logic BC1; logic BC2; } el2_ic_tag_ext_in_pkt_t; typedef struct packed { logic select; logic match; logic store; logic load; logic execute; logic m; logic [31:0] tdata2; } el2_trigger_pkt_t; typedef struct packed { logic [70:0] icache_wrdata; // {dicad1[1:0], dicad0h[31:0], dicad0[31:0]} logic [16:0] icache_dicawics; // Arraysel:24, Waysel:21:20, Index:16:3 logic icache_rd_valid; logic icache_wr_valid; } el2_cache_debug_pkt_t; typedef enum logic [2:0] { NONE = 3'b000, READ = 3'b001, WRITE = 3'b010, EXEC = 3'b100 } el2_pmp_type_pkt_t; typedef enum logic [1:0] { OFF = 2'b00, TOR = 2'b01, NA4 = 2'b10, NAPOT = 2'b11 } el2_pmp_mode_pkt_t; typedef struct packed { logic lock; logic [1:0] reserved; el2_pmp_mode_pkt_t mode; logic execute; logic write; logic read; } el2_pmp_cfg_pkt_t; typedef struct packed { logic RLB; logic MMWP; logic MML; } el2_mseccfg_pkt_t; //`endif endpackage // el2_pkg ================================================ FILE: design/lib/ahb_to_axi4.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // Owner: // Function: AHB to AXI4 Bridge // Comments: // //******************************************************************************** module ahb_to_axi4 import el2_pkg::*; #( TAG = 1, CHECK_RANGES = 1, `include "el2_param.vh" ) ( input clk, input rst_l, /* pragma coverage off */ input scan_mode, /* pragma coverage on */ input bus_clk_en, input clk_override, // AXI signals // AXI Write Channels output logic axi_awvalid, input logic axi_awready, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [TAG-1:0] axi_awid, /*pragma coverage on*/ output logic [31:0] axi_awaddr, output logic [2:0] axi_awsize, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [2:0] axi_awprot, output logic [7:0] axi_awlen, output logic [1:0] axi_awburst, /*pragma coverage on*/ output logic axi_wvalid, input logic axi_wready, output logic [63:0] axi_wdata, output logic [7:0] axi_wstrb, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic axi_wlast, /*pragma coverage on*/ input logic axi_bvalid, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic axi_bready, /*pragma coverage on*/ input logic [1:0] axi_bresp, /* Exclude unused AXI rid since it has no equivalent in AHB */ /*pragma coverage off*/ input logic [TAG-1:0] axi_bid, /*pragma coverage on*/ // AXI Read Channels output logic axi_arvalid, input logic axi_arready, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [TAG-1:0] axi_arid, /*pragma coverage on*/ output logic [31:0] axi_araddr, output logic [2:0] axi_arsize, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [2:0] axi_arprot, output logic [7:0] axi_arlen, output logic [1:0] axi_arburst, /*pragma coverage on*/ input logic axi_rvalid, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic axi_rready, /*pragma coverage on*/ /* Exclude unused AXI rid since it has no equivalent in AHB */ /*pragma coverage off*/ input logic [TAG-1:0] axi_rid, /*pragma coverage on*/ input logic [63:0] axi_rdata, input logic [1:0] axi_rresp, // AHB-Lite signals input logic [31:0] ahb_haddr, // ahb bus address // Exclude input signals that are unused in this file (their AXI equivalents // are tied to constants) /*pragma coverage off*/ input logic [2:0] ahb_hburst, // tied to 0 input logic ahb_hmastlock, // tied to 0 input logic [3:0] ahb_hprot, // tied to 4'b0011 /*pragma coverage on*/ input logic [2:0] ahb_hsize, // size of bus transaction (possible values 0,1,2,3) input logic [1:0] ahb_htrans, // Transaction type (possible values 0,2 only right now) input logic ahb_hwrite, // ahb bus write input logic [63:0] ahb_hwdata, // ahb bus write data input logic ahb_hsel, // this slave was selected input logic ahb_hreadyin, // previous hready was accepted or not output logic [63:0] ahb_hrdata, // ahb bus read data output logic ahb_hreadyout, // slave ready to accept transaction output logic ahb_hresp // slave response (high indicates erro) ); logic [7:0] master_wstrb; typedef enum logic [1:0] { IDLE = 2'b00, // Nothing in the buffer. No commands yet recieved WR = 2'b01, // Write Command recieved RD = 2'b10, // Read Command recieved PEND = 2'b11 // Waiting on Read Data from core } state_t; state_t buf_state, buf_nxtstate; logic buf_state_en; // Buffer signals (one entry buffer) logic buf_read_error_in, buf_read_error; logic [63:0] buf_rdata; logic ahb_hready; logic ahb_hready_q; logic [1:0] ahb_htrans_in, ahb_htrans_q; logic [2:0] ahb_hsize_q; logic ahb_hwrite_q; logic [31:0] ahb_haddr_q; logic ahb_hresp_q; // signals needed for the read data coming back from the core and to block any further commands as AHB is a blocking bus logic buf_rdata_en; logic ahb_addr_clk_en, buf_rdata_clk_en; logic bus_clk, ahb_addr_clk, buf_rdata_clk; // Command buffer is the holding station where we convert to AXI and send to core logic cmdbuf_wr_en, cmdbuf_rst; logic cmdbuf_full; logic cmdbuf_vld, cmdbuf_write; logic [1:0] cmdbuf_size; logic [7:0] cmdbuf_wstrb; logic [31:0] cmdbuf_addr; logic [63:0] cmdbuf_wdata; // FSM to control the bus states and when to block the hready and load the command buffer always_comb begin buf_nxtstate = IDLE; buf_state_en = 1'b0; buf_rdata_en = 1'b0; // signal to load the buffer when the core sends read data back buf_read_error_in = 1'b0; // signal indicating that an error came back with the read from the core cmdbuf_wr_en = 1'b0; // all clear from the gasket to load the buffer with the command for reads, command/dat for writes case (buf_state) IDLE: begin // No commands recieved buf_nxtstate = ahb_hwrite ? WR : RD; buf_state_en = ahb_hready & ahb_htrans[1] & ahb_hsel; // only transition on a valid hrtans end WR: begin // Write command recieved last cycle buf_nxtstate = (ahb_hresp | (ahb_htrans[1:0] == 2'b0) | ~ahb_hsel) ? IDLE : ahb_hwrite ? WR : RD; buf_state_en = (~cmdbuf_full | ahb_hresp) ; cmdbuf_wr_en = ~cmdbuf_full & ~(ahb_hresp | ((ahb_htrans[1:0] == 2'b01) & ahb_hsel)); // Dont send command to the buffer in case of an error or when the master is not ready with the data now. end RD: begin // Read command recieved last cycle. buf_nxtstate = ahb_hresp ? IDLE :PEND; // If error go to idle, else wait for read data buf_state_en = (~cmdbuf_full | ahb_hresp); // only when command can go, or if its an error cmdbuf_wr_en = ~ahb_hresp & ~cmdbuf_full; // send command only when no error end PEND: begin // Read Command has been sent. Waiting on Data. buf_nxtstate = IDLE; // go back for next command and present data next cycle buf_state_en = axi_rvalid & ~cmdbuf_write; // read data is back buf_rdata_en = buf_state_en; // buffer the read data coming back from core buf_read_error_in = buf_state_en & |axi_rresp[1:0]; // buffer error flag if return has Error ( ECC ) end endcase end // always_comb begin rvdffs_fpga #($bits(state_t)) state_reg (.*, .din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk)); assign master_wstrb[7:0] = ({8{ahb_hsize_q[2:0] == 3'b0}} & (8'b1 << ahb_haddr_q[2:0])) | ({8{ahb_hsize_q[2:0] == 3'b1}} & (8'b11 << ahb_haddr_q[2:0])) | ({8{ahb_hsize_q[2:0] == 3'b10}} & (8'b1111 << ahb_haddr_q[2:0])) | ({8{ahb_hsize_q[2:0] == 3'b11}} & 8'b1111_1111); // AHB signals assign ahb_hreadyout = ahb_hresp ? (ahb_hresp_q & ~ahb_hready_q) : ((~cmdbuf_full | (buf_state == IDLE)) & ~(buf_state == RD | buf_state == PEND) & ~buf_read_error); assign ahb_hready = ahb_hreadyout & ahb_hreadyin; assign ahb_htrans_in[1:0] = {2{ahb_hsel}} & ahb_htrans[1:0]; assign ahb_hrdata[63:0] = buf_rdata[63:0]; if (CHECK_RANGES) begin // Miscellaneous signals logic ahb_addr_in_dccm, ahb_addr_in_iccm, ahb_addr_in_pic; logic ahb_addr_in_dccm_region_nc, ahb_addr_in_iccm_region_nc, ahb_addr_in_pic_region_nc; assign ahb_hresp = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE) & ((~(ahb_addr_in_dccm | ahb_addr_in_iccm)) | // request not for ICCM or DCCM ((ahb_addr_in_iccm | (ahb_addr_in_dccm & ahb_hwrite_q)) & ~((ahb_hsize_q[1:0] == 2'b10) | (ahb_hsize_q[1:0] == 2'b11))) | // ICCM Rd/Wr OR DCCM Wr not the right size ((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0]) | // HW size but unaligned ((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) | // W size but unaligned ((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) | // DW size but unaligned buf_read_error | // Read ECC error (ahb_hresp_q & ~ahb_hready_q); // Address check dccm rvrangecheck #(.CCM_SADR(pt.DCCM_SADR), .CCM_SIZE(pt.DCCM_SIZE)) addr_dccm_rangecheck ( .addr(ahb_haddr_q[31:0]), .in_range(ahb_addr_in_dccm), .in_region(ahb_addr_in_dccm_region_nc) ); // Address check iccm if (pt.ICCM_ENABLE == 1) begin: GenICCM rvrangecheck #(.CCM_SADR(pt.ICCM_SADR), .CCM_SIZE(pt.ICCM_SIZE)) addr_iccm_rangecheck ( .addr(ahb_haddr_q[31:0]), .in_range(ahb_addr_in_iccm), .in_region(ahb_addr_in_iccm_region_nc) ); end else begin: GenNoICCM assign ahb_addr_in_iccm = '0; assign ahb_addr_in_iccm_region_nc = '0; end // PIC memory address check rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR), .CCM_SIZE(pt.PIC_SIZE)) addr_pic_rangecheck ( .addr(ahb_haddr_q[31:0]), .in_range(ahb_addr_in_pic), .in_region(ahb_addr_in_pic_region_nc) ); end else begin // !CHECK_RANGES assign ahb_hresp = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE) & (((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0]) | // HW size but unaligned ((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) | // W size but unaligned ((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) | // DW size but unaligned buf_read_error | // Read ECC error (ahb_hresp_q & ~ahb_hready_q); end // CHECK_RANGES // Buffer signals - needed for the read data and ECC error response rvdff_fpga #(.WIDTH(64)) buf_rdata_ff (.din(axi_rdata[63:0]), .dout(buf_rdata[63:0]), .clk(buf_rdata_clk), .clken(buf_rdata_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(1)) buf_read_error_ff(.din(buf_read_error_in), .dout(buf_read_error), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); // buf_read_error will be high only one cycle // All the Master signals are captured before presenting it to the command buffer. We check for Hresp before sending it to the cmd buffer. rvdff_fpga #(.WIDTH(1)) hresp_ff (.din(ahb_hresp), .dout(ahb_hresp_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(1)) hready_ff (.din(ahb_hready), .dout(ahb_hready_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(2)) htrans_ff (.din(ahb_htrans_in[1:0]), .dout(ahb_htrans_q[1:0]), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(3)) hsize_ff (.din(ahb_hsize[2:0]), .dout(ahb_hsize_q[2:0]), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(1)) hwrite_ff (.din(ahb_hwrite), .dout(ahb_hwrite_q), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(32)) haddr_ff (.din(ahb_haddr[31:0]), .dout(ahb_haddr_q[31:0]), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*); // Command Buffer - Holding for the commands to be sent for the AXI. It will be converted to the AXI signals. assign cmdbuf_rst = (((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)) & ~cmdbuf_wr_en) | (ahb_hresp & ~cmdbuf_write); assign cmdbuf_full = (cmdbuf_vld & ~((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready))); rvdffsc_fpga #(.WIDTH(1)) cmdbuf_vldff (.din(1'b1), .dout(cmdbuf_vld), .en(cmdbuf_wr_en), .clear(cmdbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(1)) cmdbuf_writeff (.din(ahb_hwrite_q), .dout(cmdbuf_write), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(2)) cmdbuf_sizeff (.din(ahb_hsize_q[1:0]), .dout(cmdbuf_size[1:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(8)) cmdbuf_wstrbff (.din(master_wstrb[7:0]), .dout(cmdbuf_wstrb[7:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffe #(.WIDTH(32)) cmdbuf_addrff (.din(ahb_haddr_q[31:0]), .dout(cmdbuf_addr[31:0]), .en(cmdbuf_wr_en & bus_clk_en), .clk(clk), .*); rvdffe #(.WIDTH(64)) cmdbuf_wdataff (.din(ahb_hwdata[63:0]), .dout(cmdbuf_wdata[63:0]), .en(cmdbuf_wr_en & bus_clk_en), .clk(clk), .*); // AXI Write Command Channel assign axi_awvalid = cmdbuf_vld & cmdbuf_write; assign axi_awid[TAG-1:0] = '0; assign axi_awaddr[31:0] = cmdbuf_addr[31:0]; assign axi_awsize[2:0] = {1'b0, cmdbuf_size[1:0]}; assign axi_awprot[2:0] = 3'b0; assign axi_awlen[7:0] = '0; assign axi_awburst[1:0] = 2'b01; // AXI Write Data Channel - This is tied to the command channel as we only write the command buffer once we have the data. assign axi_wvalid = cmdbuf_vld & cmdbuf_write; assign axi_wdata[63:0] = cmdbuf_wdata[63:0]; assign axi_wstrb[7:0] = cmdbuf_wstrb[7:0]; assign axi_wlast = 1'b1; // AXI Write Response - Always ready. AHB does not require a write response. assign axi_bready = 1'b1; // AXI Read Channels assign axi_arvalid = cmdbuf_vld & ~cmdbuf_write; assign axi_arid[TAG-1:0] = '0; assign axi_araddr[31:0] = cmdbuf_addr[31:0]; assign axi_arsize[2:0] = {1'b0, cmdbuf_size[1:0]}; assign axi_arprot = 3'b0; assign axi_arlen[7:0] = '0; assign axi_arburst[1:0] = 2'b01; // AXI Read Response Channel - Always ready as AHB reads are blocking and the the buffer is available for the read coming back always. assign axi_rready = 1'b1; // Clock header logic assign ahb_addr_clk_en = bus_clk_en & (ahb_hready & ahb_htrans[1]); assign buf_rdata_clk_en = bus_clk_en & buf_rdata_en; `ifdef RV_FPGA_OPTIMIZE assign bus_clk = 1'b0; assign ahb_addr_clk = 1'b0; assign buf_rdata_clk = 1'b0; `else rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*); rvclkhdr ahb_addr_cgc (.en(ahb_addr_clk_en), .l1clk(ahb_addr_clk), .*); rvclkhdr buf_rdata_cgc (.en(buf_rdata_clk_en), .l1clk(buf_rdata_clk), .*); `endif `ifdef RV_ASSERT_ON property ahb_error_protocol; @(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp)); endproperty assert_ahb_error_protocol: assert property (ahb_error_protocol) else $display("Bus Error with hReady isn't preceded with Bus Error without hready"); `endif endmodule // ahb_to_axi4 ================================================ FILE: design/lib/axi4_to_ahb.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // Owner: // Function: AXI4 -> AHB Bridge // Comments: // //******************************************************************************** module axi4_to_ahb import el2_pkg::*; #( `include "el2_param.vh" ,parameter TAG = 1) ( input clk, input free_clk, input rst_l, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input scan_mode, /*pragma coverage on*/ input bus_clk_en, input clk_override, input dec_tlu_force_halt, // AXI signals // AXI Write Channels input logic axi_awvalid, output logic axi_awready, input logic [TAG-1:0] axi_awid, input logic [31:0] axi_awaddr, input logic [2:0] axi_awsize, input logic [2:0] axi_awprot, input logic axi_wvalid, output logic axi_wready, input logic [63:0] axi_wdata, input logic [7:0] axi_wstrb, input logic axi_wlast, output logic axi_bvalid, input logic axi_bready, output logic [1:0] axi_bresp, output logic [TAG-1:0] axi_bid, // AXI Read Channels input logic axi_arvalid, output logic axi_arready, input logic [TAG-1:0] axi_arid, input logic [31:0] axi_araddr, input logic [2:0] axi_arsize, input logic [2:0] axi_arprot, output logic axi_rvalid, input logic axi_rready, output logic [TAG-1:0] axi_rid, output logic [63:0] axi_rdata, output logic [1:0] axi_rresp, output logic axi_rlast, // AHB-Lite signals output logic [31:0] ahb_haddr, // ahb bus address /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [2:0] ahb_hburst, // tied to 0 output logic ahb_hmastlock, // tied to 0 /*pragma coverage on*/ output logic [3:0] ahb_hprot, // [3:1] are tied to 3'b001 output logic [2:0] ahb_hsize, // size of bus transaction (possible values 0,1,2,3) output logic [1:0] ahb_htrans, // Transaction type (possible values 0,2 only right now) output logic ahb_hwrite, // ahb bus write output logic [63:0] ahb_hwdata, // ahb bus write data input logic [63:0] ahb_hrdata, // ahb bus read data input logic ahb_hready, // slave ready to accept transaction input logic ahb_hresp // slave response (high indicates erro) ); localparam ID = 1; localparam PRTY = 1; typedef enum logic [3:0] { IDLE = 4'b0000, CMD_RD = 4'b0001, CMD_WR = 4'b1001, DATA_RD = 4'b0010, DATA_WR = 4'b1010, DONE_RD = 4'b0011, DONE_WR = 4'b1011, STREAM_RD = 4'b0101, STREAM_ERR_RD = 4'b0110 } state_t; state_t buf_state, buf_nxtstate; logic slave_valid; logic [TAG-1:0] slave_tag; logic [63:0] slave_rdata; logic [3:0] slave_opc; logic wrbuf_en, wrbuf_data_en; logic wrbuf_cmd_sent, wrbuf_rst; logic wrbuf_vld; logic wrbuf_data_vld; logic [TAG-1:0] wrbuf_tag; logic [2:0] wrbuf_size; logic [31:0] wrbuf_addr; logic [63:0] wrbuf_data; logic [7:0] wrbuf_byteen; logic master_valid; logic master_ready; logic [TAG-1:0] master_tag; logic [31:0] master_addr; logic [63:0] master_wdata; logic [2:0] master_size; logic [2:0] master_opc; logic [7:0] master_byteen; // Buffer signals (one entry buffer) logic [31:0] buf_addr; logic [1:0] buf_size; logic buf_write; logic [7:0] buf_byteen; logic buf_aligned; logic [63:0] buf_data; logic [TAG-1:0] buf_tag; //Miscellaneous signals logic buf_rst; logic [TAG-1:0] buf_tag_in; logic [31:0] buf_addr_in; logic [7:0] buf_byteen_in; logic [63:0] buf_data_in; logic buf_write_in; logic buf_aligned_in; logic [2:0] buf_size_in; logic buf_state_en; logic buf_wr_en; logic buf_data_wr_en; logic slvbuf_error_en; logic wr_cmd_vld; logic cmd_done_rst, cmd_done, cmd_doneQ; logic trxn_done; logic [2:0] buf_cmd_byte_ptr, buf_cmd_byte_ptrQ, buf_cmd_nxtbyte_ptr; logic buf_cmd_byte_ptr_en; logic slave_valid_pre; logic ahb_hready_q; logic ahb_hresp_q; logic [1:0] ahb_htrans_q; logic ahb_hwrite_q; logic [63:0] ahb_hrdata_q; logic slvbuf_write; logic slvbuf_error; logic [TAG-1:0] slvbuf_tag; logic slvbuf_error_in; logic slvbuf_wr_en; logic bypass_en; logic rd_bypass_idle; logic last_addr_en; logic [31:0] last_bus_addr; // Clocks logic buf_clken; logic ahbm_data_clken; logic buf_clk; logic bus_clk; logic ahbm_data_clk; logic dec_tlu_force_halt_bus, dec_tlu_force_halt_bus_ns, dec_tlu_force_halt_bus_q; // Function to get the length from byte enable function automatic logic [1:0] get_write_size; input logic [7:0] byteen; logic [1:0] size; size[1:0] = (2'b11 & {2{(byteen[7:0] == 8'hff)}}) | (2'b10 & {2{((byteen[7:0] == 8'hf0) | (byteen[7:0] == 8'h0f))}}) | (2'b01 & {2{((byteen[7:0] == 8'hc0) | (byteen[7:0] == 8'h30) | (byteen[7:0] == 8'h0c) | (byteen[7:0] == 8'h03))}}); return size[1:0]; endfunction // get_write_size // Function to get the length from byte enable function automatic logic [2:0] get_write_addr; input logic [7:0] byteen; logic [2:0] addr; addr[2:0] = (3'h0 & {3{((byteen[7:0] == 8'hff) | (byteen[7:0] == 8'h0f) | (byteen[7:0] == 8'h03))}}) | (3'h2 & {3{(byteen[7:0] == 8'h0c)}}) | (3'h4 & {3{((byteen[7:0] == 8'hf0) | (byteen[7:0] == 8'h03))}}) | (3'h6 & {3{(byteen[7:0] == 8'hc0)}}); return addr[2:0]; endfunction // get_write_addr // Function to get the next byte pointer function automatic logic [2:0] get_nxtbyte_ptr (logic [2:0] current_byte_ptr, logic [7:0] byteen, logic get_next); logic [2:0] start_ptr; logic found; found = '0; get_nxtbyte_ptr[2:0] = 3'd0; start_ptr[2:0] = get_next ? (current_byte_ptr[2:0] + 3'b1) : current_byte_ptr[2:0]; for (int j=0; j<8; j++) begin if (~found) begin get_nxtbyte_ptr[2:0] = 3'(j); found |= (byteen[j] & (3'(j) >= start_ptr[2:0])) ; end end endfunction // get_nextbyte_ptr // Create bus synchronized version of force halt assign dec_tlu_force_halt_bus = dec_tlu_force_halt | dec_tlu_force_halt_bus_q; assign dec_tlu_force_halt_bus_ns = ~bus_clk_en & dec_tlu_force_halt_bus; rvdff #(.WIDTH(1)) force_halt_busff(.din(dec_tlu_force_halt_bus_ns), .dout(dec_tlu_force_halt_bus_q), .clk(free_clk), .*); // Write buffer assign wrbuf_en = axi_awvalid & axi_awready & master_ready; assign wrbuf_data_en = axi_wvalid & axi_wready & master_ready; assign wrbuf_cmd_sent = master_valid & master_ready & (master_opc[2:1] == 2'b01); assign wrbuf_rst = (wrbuf_cmd_sent & ~wrbuf_en) | dec_tlu_force_halt_bus; assign axi_awready = ~(wrbuf_vld & ~wrbuf_cmd_sent) & master_ready; assign axi_wready = ~(wrbuf_data_vld & ~wrbuf_cmd_sent) & master_ready; assign axi_arready = ~(wrbuf_vld & wrbuf_data_vld) & master_ready; assign axi_rlast = 1'b1; assign wr_cmd_vld = (wrbuf_vld & wrbuf_data_vld); assign master_valid = wr_cmd_vld | axi_arvalid; assign master_tag[TAG-1:0] = wr_cmd_vld ? wrbuf_tag[TAG-1:0] : axi_arid[TAG-1:0]; assign master_opc[2:0] = wr_cmd_vld ? 3'b011 : 3'b0; assign master_addr[31:0] = wr_cmd_vld ? wrbuf_addr[31:0] : axi_araddr[31:0]; assign master_size[2:0] = wr_cmd_vld ? wrbuf_size[2:0] : axi_arsize[2:0]; assign master_byteen[7:0] = wrbuf_byteen[7:0]; assign master_wdata[63:0] = wrbuf_data[63:0]; // AXI response channel signals assign axi_bvalid = slave_valid & slave_opc[3]; assign axi_bresp[1:0] = slave_opc[0] ? 2'b10 : (slave_opc[1] ? 2'b11 : 2'b0); assign axi_bid[TAG-1:0] = slave_tag[TAG-1:0]; assign axi_rvalid = slave_valid & (slave_opc[3:2] == 2'b0); assign axi_rresp[1:0] = slave_opc[0] ? 2'b10 : (slave_opc[1] ? 2'b11 : 2'b0); assign axi_rid[TAG-1:0] = slave_tag[TAG-1:0]; assign axi_rdata[63:0] = slave_rdata[63:0]; // FIFO state machine always_comb begin buf_nxtstate = IDLE; buf_state_en = 1'b0; buf_wr_en = 1'b0; buf_data_wr_en = 1'b0; slvbuf_error_in = 1'b0; slvbuf_error_en = 1'b0; buf_write_in = 1'b0; cmd_done = 1'b0; trxn_done = 1'b0; buf_cmd_byte_ptr_en = 1'b0; buf_cmd_byte_ptr[2:0] = '0; slave_valid_pre = 1'b0; master_ready = 1'b0; ahb_htrans[1:0] = 2'b0; slvbuf_wr_en = 1'b0; bypass_en = 1'b0; rd_bypass_idle = 1'b0; case (buf_state) IDLE: begin master_ready = 1'b1; buf_write_in = (master_opc[2:1] == 2'b01); buf_nxtstate = buf_write_in ? CMD_WR : CMD_RD; buf_state_en = master_valid & master_ready; buf_wr_en = buf_state_en; buf_data_wr_en = buf_state_en & (buf_nxtstate == CMD_WR); buf_cmd_byte_ptr_en = buf_state_en; buf_cmd_byte_ptr[2:0] = buf_write_in ? get_nxtbyte_ptr(3'b0,buf_byteen_in[7:0],1'b0) : master_addr[2:0]; bypass_en = buf_state_en; rd_bypass_idle = bypass_en & (buf_nxtstate == CMD_RD); ahb_htrans[1:0] = {2{bypass_en}} & 2'b10; end CMD_RD: begin buf_nxtstate = (master_valid & (master_opc[2:0] == 3'b000))? STREAM_RD : DATA_RD; buf_state_en = ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) & ~ahb_hwrite_q; cmd_done = buf_state_en & ~master_valid; slvbuf_wr_en = buf_state_en; master_ready = buf_state_en & (buf_nxtstate == STREAM_RD); buf_wr_en = master_ready; bypass_en = master_ready & master_valid; buf_cmd_byte_ptr[2:0] = bypass_en ? master_addr[2:0] : buf_addr[2:0]; ahb_htrans[1:0] = 2'b10 & {2{~buf_state_en | bypass_en}}; end STREAM_RD: begin master_ready = (ahb_hready_q & ~ahb_hresp_q) & ~(master_valid & master_opc[2:1] == 2'b01); buf_wr_en = (master_valid & master_ready & (master_opc[2:0] == 3'b000)); // update the fifo if we are streaming the read commands buf_nxtstate = ahb_hresp_q ? STREAM_ERR_RD : (buf_wr_en ? STREAM_RD : DATA_RD); // assuming that the master accpets the slave response right away. buf_state_en = (ahb_hready_q | ahb_hresp_q); buf_data_wr_en = buf_state_en; slvbuf_error_in = ahb_hresp_q; slvbuf_error_en = buf_state_en; slave_valid_pre = buf_state_en & ~ahb_hresp_q; // send a response right away if we are not going through an error response. cmd_done = buf_state_en & ~master_valid; // last one of the stream should not send a htrans bypass_en = master_ready & master_valid & (buf_nxtstate == STREAM_RD) & buf_state_en; buf_cmd_byte_ptr[2:0] = bypass_en ? master_addr[2:0] : buf_addr[2:0]; ahb_htrans[1:0] = 2'b10 & {2{~((buf_nxtstate != STREAM_RD) & buf_state_en)}}; slvbuf_wr_en = buf_wr_en; // shifting the contents from the buf to slv_buf for streaming cases end // case: STREAM_RD STREAM_ERR_RD: begin buf_nxtstate = DATA_RD; buf_state_en = ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) & ~ahb_hwrite_q; slave_valid_pre = buf_state_en; slvbuf_wr_en = buf_state_en; // Overwrite slvbuf with buffer buf_cmd_byte_ptr[2:0] = buf_addr[2:0]; ahb_htrans[1:0] = 2'b10 & {2{~buf_state_en}}; end DATA_RD: begin buf_nxtstate = DONE_RD; buf_state_en = (ahb_hready_q | ahb_hresp_q); buf_data_wr_en = buf_state_en; slvbuf_error_in= ahb_hresp_q; slvbuf_error_en= buf_state_en; slvbuf_wr_en = buf_state_en; end CMD_WR: begin buf_nxtstate = DATA_WR; trxn_done = ahb_hready_q & ahb_hwrite_q & (ahb_htrans_q[1:0] != 2'b0); buf_state_en = trxn_done; buf_cmd_byte_ptr_en = buf_state_en; slvbuf_wr_en = buf_state_en; buf_cmd_byte_ptr = trxn_done ? get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1) : buf_cmd_byte_ptrQ; cmd_done = trxn_done & (buf_aligned | (buf_cmd_byte_ptrQ == 3'b111) | (buf_byteen[get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1)] == 1'b0)); ahb_htrans[1:0] = {2{~(cmd_done | cmd_doneQ)}} & 2'b10; end DATA_WR: begin buf_state_en = (cmd_doneQ & ahb_hready_q) | ahb_hresp_q; master_ready = buf_state_en & ~ahb_hresp_q & axi_bready; // Ready to accept new command if current command done and no error buf_nxtstate = (ahb_hresp_q | ~axi_bready) ? DONE_WR : ((master_valid & master_ready) ? ((master_opc[2:1] == 2'b01) ? CMD_WR : CMD_RD) : IDLE); slvbuf_error_in = ahb_hresp_q; slvbuf_error_en = buf_state_en; buf_write_in = (master_opc[2:1] == 2'b01); buf_wr_en = buf_state_en & ((buf_nxtstate == CMD_WR) | (buf_nxtstate == CMD_RD)); buf_data_wr_en = buf_wr_en; cmd_done = (ahb_hresp_q | (ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) & ((buf_cmd_byte_ptrQ == 3'b111) | (buf_byteen[get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1)] == 1'b0)))); bypass_en = buf_state_en & buf_write_in & (buf_nxtstate == CMD_WR); // Only bypass for writes for the time being ahb_htrans[1:0] = {2{(~(cmd_done | cmd_doneQ) | bypass_en)}} & 2'b10; slave_valid_pre = buf_state_en & (buf_nxtstate != DONE_WR); trxn_done = ahb_hready_q & ahb_hwrite_q & (ahb_htrans_q[1:0] != 2'b0); buf_cmd_byte_ptr_en = trxn_done | bypass_en; buf_cmd_byte_ptr = bypass_en ? get_nxtbyte_ptr(3'b0,buf_byteen_in[7:0],1'b0) : trxn_done ? get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1) : buf_cmd_byte_ptrQ; end DONE_WR: begin buf_nxtstate = IDLE; buf_state_en = axi_bvalid & axi_bready; slvbuf_error_en = 1'b1; slave_valid_pre = 1'b1; end DONE_RD: begin buf_nxtstate = IDLE; buf_state_en = axi_rvalid & axi_rready; // axi_rlast == 1 slvbuf_error_en = 1'b1; slave_valid_pre = 1'b1; end // `buf_state` is an enum and all the members are handled above, so the default case is excluded from coverge. /*pragma coverage off*/ default: begin buf_nxtstate = IDLE; buf_state_en = 1'b1; end /*pragma coverage on*/ endcase end assign buf_rst = dec_tlu_force_halt_bus; assign cmd_done_rst = slave_valid_pre; assign buf_addr_in[31:3] = master_addr[31:3]; assign buf_addr_in[2:0] = (buf_aligned_in & (master_opc[2:1] == 2'b01)) ? get_write_addr(master_byteen[7:0]) : master_addr[2:0]; assign buf_tag_in[TAG-1:0] = master_tag[TAG-1:0]; assign buf_byteen_in[7:0] = wrbuf_byteen[7:0]; assign buf_data_in[63:0] = (buf_state == DATA_RD) ? ahb_hrdata_q[63:0] : master_wdata[63:0]; assign buf_size_in[1:0] = (buf_aligned_in & (master_size[1:0] == 2'b11) & (master_opc[2:1] == 2'b01)) ? get_write_size(master_byteen[7:0]) : master_size[1:0]; assign buf_aligned_in = (master_opc[2:0] == 3'b0) | // reads are always aligned since they are either DW or sideeffects (master_size[1:0] == 2'b0) | (master_size[1:0] == 2'b01) | (master_size[1:0] == 2'b10) | // Always aligned for Byte/HW/Word since they can be only for non-idempotent. IFU/SB are always aligned ((master_size[1:0] == 2'b11) & ((master_byteen[7:0] == 8'h3) | (master_byteen[7:0] == 8'hc) | (master_byteen[7:0] == 8'h30) | (master_byteen[7:0] == 8'hc0) | (master_byteen[7:0] == 8'hf) | (master_byteen[7:0] == 8'hf0) | (master_byteen[7:0] == 8'hff))); // Generate the ahb signals assign ahb_haddr[31:3] = bypass_en ? master_addr[31:3] : buf_addr[31:3]; assign ahb_haddr[2:0] = {3{(ahb_htrans == 2'b10)}} & buf_cmd_byte_ptr[2:0]; // Trxn should be aligned during IDLE assign ahb_hsize[2:0] = bypass_en ? {1'b0, ({2{buf_aligned_in}} & buf_size_in[1:0])} : {1'b0, ({2{buf_aligned}} & buf_size[1:0])}; // Send the full size for aligned trxn assign ahb_hburst[2:0] = 3'b0; assign ahb_hmastlock = 1'b0; assign ahb_hprot[3:0] = {3'b001,~axi_arprot[2]}; assign ahb_hwrite = bypass_en ? (master_opc[2:1] == 2'b01) : buf_write; assign ahb_hwdata[63:0] = buf_data[63:0]; assign slave_valid = slave_valid_pre;// & (~slvbuf_posted_write | slvbuf_error); assign slave_opc[3:2] = slvbuf_write ? 2'b11 : 2'b00; assign slave_opc[1:0] = {2{slvbuf_error}} & 2'b10; assign slave_rdata[63:0] = slvbuf_error ? {2{last_bus_addr[31:0]}} : ((buf_state == DONE_RD) ? buf_data[63:0] : ahb_hrdata_q[63:0]); assign slave_tag[TAG-1:0] = slvbuf_tag[TAG-1:0]; assign last_addr_en = (ahb_htrans[1:0] != 2'b0) & ahb_hready & ahb_hwrite ; rvdffsc_fpga #(.WIDTH(1)) wrbuf_vldff (.din(1'b1), .dout(wrbuf_vld), .en(wrbuf_en), .clear(wrbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffsc_fpga #(.WIDTH(1)) wrbuf_data_vldff(.din(1'b1), .dout(wrbuf_data_vld), .en(wrbuf_data_en), .clear(wrbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(TAG)) wrbuf_tagff (.din(axi_awid[TAG-1:0]), .dout(wrbuf_tag[TAG-1:0]), .en(wrbuf_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(3)) wrbuf_sizeff (.din(axi_awsize[2:0]), .dout(wrbuf_size[2:0]), .en(wrbuf_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffe #(.WIDTH(32)) wrbuf_addrff (.din(axi_awaddr[31:0]), .dout(wrbuf_addr[31:0]), .en(wrbuf_en & bus_clk_en), .clk(clk), .*); rvdffe #(.WIDTH(64)) wrbuf_dataff (.din(axi_wdata[63:0]), .dout(wrbuf_data[63:0]), .en(wrbuf_data_en & bus_clk_en), .clk(clk), .*); rvdffs_fpga #(.WIDTH(8)) wrbuf_byteenff (.din(axi_wstrb[7:0]), .dout(wrbuf_byteen[7:0]), .en(wrbuf_data_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(32)) last_bus_addrff (.din(ahb_haddr[31:0]), .dout(last_bus_addr[31:0]), .en(last_addr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffsc_fpga #(.WIDTH($bits(state_t))) buf_state_ff (.din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clear(buf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(1)) buf_writeff (.din(buf_write_in), .dout(buf_write), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(TAG)) buf_tagff (.din(buf_tag_in[TAG-1:0]), .dout(buf_tag[TAG-1:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*); rvdffe #(.WIDTH(32)) buf_addrff (.din(buf_addr_in[31:0]), .dout(buf_addr[31:0]), .en(buf_wr_en & bus_clk_en), .clk(clk), .*); rvdffs_fpga #(.WIDTH(2)) buf_sizeff (.din(buf_size_in[1:0]), .dout(buf_size[1:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(1)) buf_alignedff (.din(buf_aligned_in), .dout(buf_aligned), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(8)) buf_byteenff (.din(buf_byteen_in[7:0]), .dout(buf_byteen[7:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*); rvdffe #(.WIDTH(64)) buf_dataff (.din(buf_data_in[63:0]), .dout(buf_data[63:0]), .en(buf_data_wr_en & bus_clk_en), .clk(clk), .*); rvdffs_fpga #(.WIDTH(1)) slvbuf_writeff (.din(buf_write), .dout(slvbuf_write), .en(slvbuf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(TAG)) slvbuf_tagff (.din(buf_tag[TAG-1:0]), .dout(slvbuf_tag[TAG-1:0]), .en(slvbuf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(1)) slvbuf_errorff (.din(slvbuf_error_in), .dout(slvbuf_error), .en(slvbuf_error_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffsc_fpga #(.WIDTH(1)) buf_cmd_doneff (.din(1'b1), .dout(cmd_doneQ), .en(cmd_done), .clear(cmd_done_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(3)) buf_cmd_byte_ptrff (.din(buf_cmd_byte_ptr[2:0]), .dout(buf_cmd_byte_ptrQ[2:0]), .en(buf_cmd_byte_ptr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(1)) hready_ff (.din(ahb_hready), .dout(ahb_hready_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(2)) htrans_ff (.din(ahb_htrans[1:0]), .dout(ahb_htrans_q[1:0]), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(1)) hwrite_ff (.din(ahb_hwrite), .dout(ahb_hwrite_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(1)) hresp_ff (.din(ahb_hresp), .dout(ahb_hresp_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(64)) hrdata_ff (.din(ahb_hrdata[63:0]), .dout(ahb_hrdata_q[63:0]), .clk(ahbm_data_clk), .clken(ahbm_data_clken), .rawclk(clk), .*); // Clock headers // clock enables for ahbm addr/data assign buf_clken = bus_clk_en & (buf_wr_en | slvbuf_wr_en | clk_override); assign ahbm_data_clken = bus_clk_en & ((buf_state != IDLE) | clk_override); `ifdef RV_FPGA_OPTIMIZE assign bus_clk = 1'b0; assign buf_clk = 1'b0; assign ahbm_data_clk = 1'b0; `else rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*); rvclkhdr buf_cgc (.en(buf_clken), .l1clk(buf_clk), .*); rvclkhdr ahbm_data_cgc (.en(ahbm_data_clken), .l1clk(ahbm_data_clk), .*); `endif `ifdef RV_ASSERT_ON property ahb_trxn_aligned; @(posedge bus_clk) ahb_htrans[1] |-> ((ahb_hsize[2:0] == 3'h0) | ((ahb_hsize[2:0] == 3'h1) & (ahb_haddr[0] == 1'b0)) | ((ahb_hsize[2:0] == 3'h2) & (ahb_haddr[1:0] == 2'b0)) | ((ahb_hsize[2:0] == 3'h3) & (ahb_haddr[2:0] == 3'b0))); endproperty assert_ahb_trxn_aligned: assert property (ahb_trxn_aligned) else $display("Assertion ahb_trxn_aligned failed: ahb_htrans=2'h%h, ahb_hsize=3'h%h, ahb_haddr=32'h%h",ahb_htrans[1:0], ahb_hsize[2:0], ahb_haddr[31:0]); property ahb_error_protocol; @(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp)); endproperty assert_ahb_error_protocol: assert property (ahb_error_protocol) else $display("Bus Error with hReady isn't preceded with Bus Error without hready"); `endif endmodule // axi4_to_ahb ================================================ FILE: design/lib/beh_lib.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // all flops call the rvdff flop module rvdff #( parameter WIDTH=1, SHORT=0 ) ( input logic [WIDTH-1:0] din, input logic clk, input logic rst_l, output logic [WIDTH-1:0] dout ); if (SHORT == 1) begin assign dout = din; end else begin `ifdef RV_CLOCKGATE always @(posedge tb_top.clk) begin #0 $strobe("CG: %0t %m din %x dout %x clk %b width %d",$time,din,dout,clk,WIDTH); end `endif always_ff @(posedge clk or negedge rst_l) begin if (rst_l == 0) dout[WIDTH-1:0] <= 0; else dout[WIDTH-1:0] <= din[WIDTH-1:0]; end end endmodule // rvdff with 2:1 input mux to flop din iff sel==1 module rvdffs #( parameter WIDTH=1, SHORT=0 ) ( input logic [WIDTH-1:0] din, input logic en, input logic clk, input logic rst_l, output logic [WIDTH-1:0] dout ); if (SHORT == 1) begin : genblock assign dout = din; end else begin : genblock rvdff #(WIDTH) dffs (.din((en) ? din[WIDTH-1:0] : dout[WIDTH-1:0]), .*); end endmodule // rvdff with en and clear module rvdffsc #( parameter WIDTH=1, SHORT=0 ) ( input logic [WIDTH-1:0] din, input logic en, input logic clear, input logic clk, input logic rst_l, output logic [WIDTH-1:0] dout ); logic [WIDTH-1:0] din_new; if (SHORT == 1) begin : genblock assign dout = din; end else begin : genblock assign din_new = {WIDTH{~clear}} & (en ? din[WIDTH-1:0] : dout[WIDTH-1:0]); rvdff #(WIDTH) dffsc (.din(din_new[WIDTH-1:0]), .*); end endmodule // _fpga versions module rvdff_fpga #( parameter WIDTH=1, SHORT=0 ) ( input logic [WIDTH-1:0] din, input logic clk, input logic clken, input logic rawclk, input logic rst_l, output logic [WIDTH-1:0] dout ); if (SHORT == 1) begin : genblock assign dout = din; end else begin : genblock `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dffs (.clk(rawclk), .en(clken), .*); `else rvdff #(WIDTH) dff (.*); `endif end endmodule // rvdff with 2:1 input mux to flop din iff sel==1 module rvdffs_fpga #( parameter WIDTH=1, SHORT=0 ) ( input logic [WIDTH-1:0] din, input logic en, input logic clk, input logic clken, input logic rawclk, input logic rst_l, output logic [WIDTH-1:0] dout ); if (SHORT == 1) begin : genblock assign dout = din; end else begin : genblock `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dffs (.clk(rawclk), .en(clken & en), .*); `else rvdffs #(WIDTH) dffs (.*); `endif end endmodule // rvdff with en and clear module rvdffsc_fpga #( parameter WIDTH=1, SHORT=0 ) ( input logic [WIDTH-1:0] din, input logic en, input logic clear, input logic clk, input logic clken, input logic rawclk, input logic rst_l, output logic [WIDTH-1:0] dout ); logic [WIDTH-1:0] din_new; if (SHORT == 1) begin : genblock assign dout = din; end else begin : genblock `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dffs (.clk(rawclk), .din(din[WIDTH-1:0] & {WIDTH{~clear}}),.en((en | clear) & clken), .*); `else rvdffsc #(WIDTH) dffsc (.*); `endif end endmodule module rvdffe #( parameter WIDTH=1, SHORT=0, OVERRIDE=0 ) ( input logic [WIDTH-1:0] din, input logic en, input logic clk, input logic rst_l, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ output logic [WIDTH-1:0] dout ); logic l1clk; if (SHORT == 1) begin : genblock if (1) begin : genblock assign dout = din; end end else begin : genblock `ifndef RV_PHYSICAL if (WIDTH >= 8 || OVERRIDE==1) begin: genblock `endif `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dff ( .* ); `else rvclkhdr clkhdr ( .* ); rvdff #(WIDTH) dff (.*, .clk(l1clk)); `endif `ifndef RV_PHYSICAL end else $error("%m: rvdffe must be WIDTH >= 8"); `endif end // else: !if(SHORT == 1) endmodule // rvdffe module rvdffpcie #( parameter WIDTH=31 ) ( input logic [WIDTH-1:0] din, input logic clk, input logic rst_l, input logic en, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ output logic [WIDTH-1:0] dout ); `ifndef RV_PHYSICAL if (WIDTH == 31) begin: genblock `endif `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dff ( .* ); `else rvdfflie #(.WIDTH(WIDTH), .LEFT(19)) dff (.*); `endif `ifndef RV_PHYSICAL end else $error("%m: rvdffpcie width must be 31"); `endif endmodule // format: { LEFT, EXTRA } // LEFT # of bits will be done with rvdffie, all else EXTRA with rvdffe module rvdfflie #( parameter WIDTH=16, LEFT=8 ) ( input logic [WIDTH-1:0] din, input logic clk, input logic rst_l, input logic en, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ output logic [WIDTH-1:0] dout ); localparam EXTRA = WIDTH-LEFT; localparam LMSB = WIDTH-1; localparam LLSB = LMSB-LEFT+1; localparam XMSB = LLSB-1; localparam XLSB = LLSB-EXTRA; `ifndef RV_PHYSICAL if (WIDTH >= 16 && LEFT >= 8 && EXTRA >= 8) begin: genblock `endif `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dff ( .* ); `else rvdffiee #(LEFT) dff_left (.*, .din(din[LMSB:LLSB]), .dout(dout[LMSB:LLSB])); rvdffe #(EXTRA) dff_extra (.*, .din(din[XMSB:XLSB]), .dout(dout[XMSB:XLSB])); `endif `ifndef RV_PHYSICAL end else $error("%m: rvdfflie musb be WIDTH >= 16 && LEFT >= 8 && EXTRA >= 8"); `endif endmodule // special power flop for predict packet // format: { LEFT, RIGHT==31 } // LEFT # of bits will be done with rvdffe; RIGHT is enabled by LEFT[LSB] & en module rvdffppe #( parameter integer WIDTH = 39 ) ( input logic [WIDTH-1:0] din, input logic clk, input logic rst_l, input logic en, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ output logic [WIDTH-1:0] dout ); localparam integer RIGHT = 31; localparam integer LEFT = WIDTH - RIGHT; localparam integer LMSB = WIDTH-1; localparam integer LLSB = LMSB-LEFT+1; localparam integer RMSB = LLSB-1; localparam integer RLSB = LLSB-RIGHT; `ifndef RV_PHYSICAL if (WIDTH>=32 && LEFT>=8 && RIGHT>=8) begin: genblock `endif `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dff ( .* ); `else rvdffe #(LEFT) dff_left (.*, .din(din[LMSB:LLSB]), .dout(dout[LMSB:LLSB])); rvdffe #(RIGHT) dff_right (.*, .din(din[RMSB:RLSB]), .dout(dout[RMSB:RLSB]), .en(en & din[LLSB])); // qualify with pret `endif `ifndef RV_PHYSICAL end else $error("%m: must be WIDTH>=32 && LEFT>=8 && RIGHT>=8"); `endif endmodule module rvdffie #( parameter WIDTH=1, OVERRIDE=0 ) ( input logic [WIDTH-1:0] din, input logic clk, input logic rst_l, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ output logic [WIDTH-1:0] dout ); logic l1clk; logic en; `ifndef RV_PHYSICAL if (WIDTH >= 8 || OVERRIDE==1) begin: genblock `endif assign en = |(din ^ dout); `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dff ( .* ); `else rvclkhdr clkhdr ( .* ); rvdff #(WIDTH) dff (.*, .clk(l1clk)); `endif `ifndef RV_PHYSICAL end else $error("%m: rvdffie must be WIDTH >= 8"); `endif endmodule // ie flop but it has an .en input module rvdffiee #( parameter WIDTH=1, OVERRIDE=0 ) ( input logic [WIDTH-1:0] din, input logic clk, input logic rst_l, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ input logic en, output logic [WIDTH-1:0] dout ); logic l1clk; logic final_en; `ifndef RV_PHYSICAL if (WIDTH >= 8 || OVERRIDE==1) begin: genblock `endif assign final_en = (|(din ^ dout)) & en; `ifdef RV_FPGA_OPTIMIZE rvdffs #(WIDTH) dff ( .*, .en(final_en) ); `else rvdffe #(WIDTH) dff (.*, .en(final_en)); `endif `ifndef RV_PHYSICAL end else $error("%m: rvdffie width must be >= 8"); `endif endmodule module rvsyncss #(parameter WIDTH = 251) ( input logic clk, input logic rst_l, input logic [WIDTH-1:0] din, output logic [WIDTH-1:0] dout ); logic [WIDTH-1:0] din_ff1; rvdff #(WIDTH) sync_ff1 (.*, .din (din[WIDTH-1:0]), .dout(din_ff1[WIDTH-1:0])); rvdff #(WIDTH) sync_ff2 (.*, .din (din_ff1[WIDTH-1:0]), .dout(dout[WIDTH-1:0])); endmodule // rvsyncss module rvsyncss_fpga #(parameter WIDTH = 251) ( input logic gw_clk, input logic rawclk, input logic clken, input logic rst_l, input logic [WIDTH-1:0] din, output logic [WIDTH-1:0] dout ); logic [WIDTH-1:0] din_ff1; rvdff_fpga #(WIDTH) sync_ff1 (.*, .clk(gw_clk), .rawclk(rawclk), .clken(clken), .din (din[WIDTH-1:0]), .dout(din_ff1[WIDTH-1:0])); rvdff_fpga #(WIDTH) sync_ff2 (.*, .clk(gw_clk), .rawclk(rawclk), .clken(clken), .din (din_ff1[WIDTH-1:0]), .dout(dout[WIDTH-1:0])); endmodule // rvsyncss module rvlsadder ( input logic [31:0] rs1, input logic [11:0] offset, output logic [31:0] dout ); logic cout; logic sign; logic [31:12] rs1_inc; logic [31:12] rs1_dec; assign {cout,dout[11:0]} = {1'b0,rs1[11:0]} + {1'b0,offset[11:0]}; assign rs1_inc[31:12] = rs1[31:12] + 1; assign rs1_dec[31:12] = rs1[31:12] - 1; assign sign = offset[11]; assign dout[31:12] = ({20{ sign ^~ cout}} & rs1[31:12]) | ({20{ ~sign & cout}} & rs1_inc[31:12]) | ({20{ sign & ~cout}} & rs1_dec[31:12]); endmodule // rvlsadder // assume we only maintain pc[31:1] in the pipe module rvbradder ( input [31:1] pc, input [12:1] offset, output [31:1] dout ); logic cout; logic sign; logic [31:13] pc_inc; logic [31:13] pc_dec; assign {cout,dout[12:1]} = {1'b0,pc[12:1]} + {1'b0,offset[12:1]}; assign pc_inc[31:13] = pc[31:13] + 1; assign pc_dec[31:13] = pc[31:13] - 1; assign sign = offset[12]; assign dout[31:13] = ({19{ sign ^~ cout}} & pc[31:13]) | ({19{ ~sign & cout}} & pc_inc[31:13]) | ({19{ sign & ~cout}} & pc_dec[31:13]); endmodule // rvbradder // 2s complement circuit module rvtwoscomp #( parameter WIDTH=32 ) ( input logic [WIDTH-1:0] din, output logic [WIDTH-1:0] dout ); logic [WIDTH-1:1] dout_temp; // holding for all other bits except for the lsb. LSB is always din genvar i; for ( i = 1; i < WIDTH; i++ ) begin : flip_after_first_one assign dout_temp[i] = (|din[i-1:0]) ? ~din[i] : din[i]; end : flip_after_first_one assign dout[WIDTH-1:0] = { dout_temp[WIDTH-1:1], din[0] }; endmodule // 2'scomp // find first module rvfindfirst1 #( parameter WIDTH=32, SHIFT=$clog2(WIDTH) ) ( input logic [WIDTH-1:0] din, output logic [SHIFT-1:0] dout ); logic done; always_comb begin dout[SHIFT-1:0] = {SHIFT{1'b0}}; done = 1'b0; for ( int i = WIDTH-1; i > 0; i-- ) begin : find_first_one done |= din[i]; dout[SHIFT-1:0] += done ? 1'b0 : 1'b1; end : find_first_one end endmodule // rvfindfirst1 module rvfindfirst1hot #( parameter WIDTH=32 ) ( input logic [WIDTH-1:0] din, output logic [WIDTH-1:0] dout ); logic done; always_comb begin dout[WIDTH-1:0] = {WIDTH{1'b0}}; done = 1'b0; for ( int i = 0; i < WIDTH; i++ ) begin : find_first_one dout[i] = ~done & din[i]; done |= din[i]; end : find_first_one end endmodule // rvfindfirst1hot // mask and match function matches bits after finding the first 0 position // find first starting from LSB. Skip that location and match the rest of the bits module rvmaskandmatch #( parameter WIDTH=32 ) ( input logic [WIDTH-1:0] mask, // this will have the mask in the lower bit positions input logic [WIDTH-1:0] data, // this is what needs to be matched on the upper bits with the mask's upper bits input logic masken, // when 1 : do mask. 0 : full match output logic match ); logic [WIDTH-1:0] matchvec; logic masken_or_fullmask; assign masken_or_fullmask = masken & ~(&mask[WIDTH-1:0]); assign matchvec[0] = masken_or_fullmask | (mask[0] == data[0]); genvar i; for ( i = 1; i < WIDTH; i++ ) begin : match_after_first_zero assign matchvec[i] = (&mask[i-1:0] & masken_or_fullmask) ? 1'b1 : (mask[i] == data[i]); end : match_after_first_zero assign match = &matchvec[WIDTH-1:0]; // all bits either matched or were masked off endmodule // rvmaskandmatch // Check if the S_ADDR <= addr < E_ADDR module rvrangecheck #(CCM_SADR = 32'h0, CCM_SIZE = 128) ( input logic [31:0] addr, // Address to be checked for range output logic in_range, // S_ADDR <= start_addr < E_ADDR output logic in_region ); localparam REGION_BITS = 4; localparam MASK_BITS = 10 + $clog2(CCM_SIZE); logic [31:0] start_addr; logic [3:0] region; assign start_addr[31:0] = CCM_SADR; assign region[REGION_BITS-1:0] = start_addr[31:(32-REGION_BITS)]; assign in_region = (addr[31:(32-REGION_BITS)] == region[REGION_BITS-1:0]); if (CCM_SIZE == 48) assign in_range = (addr[31:MASK_BITS] == start_addr[31:MASK_BITS]) & ~(&addr[MASK_BITS-1 : MASK_BITS-2]); else assign in_range = (addr[31:MASK_BITS] == start_addr[31:MASK_BITS]); endmodule // rvrangechecker // 16 bit even parity generator module rveven_paritygen #(WIDTH = 16) ( input logic [WIDTH-1:0] data_in, // Data output logic parity_out // generated even parity ); assign parity_out = ^(data_in[WIDTH-1:0]) ; endmodule // rveven_paritygen module rveven_paritycheck #(WIDTH = 16) ( input logic [WIDTH-1:0] data_in, // Data input logic parity_in, output logic parity_err // Parity error ); assign parity_err = ^(data_in[WIDTH-1:0]) ^ parity_in ; endmodule // rveven_paritycheck module rvecc_encode ( input [31:0] din, output [6:0] ecc_out ); logic [5:0] ecc_out_temp; assign ecc_out_temp[0] = din[0]^din[1]^din[3]^din[4]^din[6]^din[8]^din[10]^din[11]^din[13]^din[15]^din[17]^din[19]^din[21]^din[23]^din[25]^din[26]^din[28]^din[30]; assign ecc_out_temp[1] = din[0]^din[2]^din[3]^din[5]^din[6]^din[9]^din[10]^din[12]^din[13]^din[16]^din[17]^din[20]^din[21]^din[24]^din[25]^din[27]^din[28]^din[31]; assign ecc_out_temp[2] = din[1]^din[2]^din[3]^din[7]^din[8]^din[9]^din[10]^din[14]^din[15]^din[16]^din[17]^din[22]^din[23]^din[24]^din[25]^din[29]^din[30]^din[31]; assign ecc_out_temp[3] = din[4]^din[5]^din[6]^din[7]^din[8]^din[9]^din[10]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25]; assign ecc_out_temp[4] = din[11]^din[12]^din[13]^din[14]^din[15]^din[16]^din[17]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25]; assign ecc_out_temp[5] = din[26]^din[27]^din[28]^din[29]^din[30]^din[31]; assign ecc_out[6:0] = {(^din[31:0])^(^ecc_out_temp[5:0]),ecc_out_temp[5:0]}; endmodule // rvecc_encode module rvecc_decode ( input en, input [31:0] din, input [6:0] ecc_in, input sed_ded, // only do detection and no correction. Used for the I$ output [31:0] dout, output [6:0] ecc_out, output single_ecc_error, output double_ecc_error ); logic [6:0] ecc_check; logic [38:0] error_mask; logic [38:0] din_plus_parity, dout_plus_parity; // Generate the ecc bits assign ecc_check[0] = ecc_in[0]^din[0]^din[1]^din[3]^din[4]^din[6]^din[8]^din[10]^din[11]^din[13]^din[15]^din[17]^din[19]^din[21]^din[23]^din[25]^din[26]^din[28]^din[30]; assign ecc_check[1] = ecc_in[1]^din[0]^din[2]^din[3]^din[5]^din[6]^din[9]^din[10]^din[12]^din[13]^din[16]^din[17]^din[20]^din[21]^din[24]^din[25]^din[27]^din[28]^din[31]; assign ecc_check[2] = ecc_in[2]^din[1]^din[2]^din[3]^din[7]^din[8]^din[9]^din[10]^din[14]^din[15]^din[16]^din[17]^din[22]^din[23]^din[24]^din[25]^din[29]^din[30]^din[31]; assign ecc_check[3] = ecc_in[3]^din[4]^din[5]^din[6]^din[7]^din[8]^din[9]^din[10]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25]; assign ecc_check[4] = ecc_in[4]^din[11]^din[12]^din[13]^din[14]^din[15]^din[16]^din[17]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25]; assign ecc_check[5] = ecc_in[5]^din[26]^din[27]^din[28]^din[29]^din[30]^din[31]; // This is the parity bit assign ecc_check[6] = ((^din[31:0])^(^ecc_in[6:0])) & ~sed_ded; assign single_ecc_error = en & (ecc_check[6:0] != 0) & ecc_check[6]; // this will never be on for sed_ded assign double_ecc_error = en & (ecc_check[6:0] != 0) & ~ecc_check[6]; // all errors in the sed_ded case will be recorded as DE // Generate the mask for error correctiong for (genvar i=1; i<40; i++) begin assign error_mask[i-1] = (ecc_check[5:0] == i); end // Generate the corrected data assign din_plus_parity[38:0] = {ecc_in[6], din[31:26], ecc_in[5], din[25:11], ecc_in[4], din[10:4], ecc_in[3], din[3:1], ecc_in[2], din[0], ecc_in[1:0]}; assign dout_plus_parity[38:0] = single_ecc_error ? (error_mask[38:0] ^ din_plus_parity[38:0]) : din_plus_parity[38:0]; assign dout[31:0] = {dout_plus_parity[37:32], dout_plus_parity[30:16], dout_plus_parity[14:8], dout_plus_parity[6:4], dout_plus_parity[2]}; assign ecc_out[6:0] = {(dout_plus_parity[38] ^ (ecc_check[6:0] == 7'b1000000)), dout_plus_parity[31], dout_plus_parity[15], dout_plus_parity[7], dout_plus_parity[3], dout_plus_parity[1:0]}; endmodule // rvecc_decode module rvecc_encode_64 ( input [63:0] din, output [6:0] ecc_out ); assign ecc_out[0] = din[0]^din[1]^din[3]^din[4]^din[6]^din[8]^din[10]^din[11]^din[13]^din[15]^din[17]^din[19]^din[21]^din[23]^din[25]^din[26]^din[28]^din[30]^din[32]^din[34]^din[36]^din[38]^din[40]^din[42]^din[44]^din[46]^din[48]^din[50]^din[52]^din[54]^din[56]^din[57]^din[59]^din[61]^din[63]; assign ecc_out[1] = din[0]^din[2]^din[3]^din[5]^din[6]^din[9]^din[10]^din[12]^din[13]^din[16]^din[17]^din[20]^din[21]^din[24]^din[25]^din[27]^din[28]^din[31]^din[32]^din[35]^din[36]^din[39]^din[40]^din[43]^din[44]^din[47]^din[48]^din[51]^din[52]^din[55]^din[56]^din[58]^din[59]^din[62]^din[63]; assign ecc_out[2] = din[1]^din[2]^din[3]^din[7]^din[8]^din[9]^din[10]^din[14]^din[15]^din[16]^din[17]^din[22]^din[23]^din[24]^din[25]^din[29]^din[30]^din[31]^din[32]^din[37]^din[38]^din[39]^din[40]^din[45]^din[46]^din[47]^din[48]^din[53]^din[54]^din[55]^din[56]^din[60]^din[61]^din[62]^din[63]; assign ecc_out[3] = din[4]^din[5]^din[6]^din[7]^din[8]^din[9]^din[10]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25]^din[33]^din[34]^din[35]^din[36]^din[37]^din[38]^din[39]^din[40]^din[49]^din[50]^din[51]^din[52]^din[53]^din[54]^din[55]^din[56]; assign ecc_out[4] = din[11]^din[12]^din[13]^din[14]^din[15]^din[16]^din[17]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25]^din[41]^din[42]^din[43]^din[44]^din[45]^din[46]^din[47]^din[48]^din[49]^din[50]^din[51]^din[52]^din[53]^din[54]^din[55]^din[56]; assign ecc_out[5] = din[26]^din[27]^din[28]^din[29]^din[30]^din[31]^din[32]^din[33]^din[34]^din[35]^din[36]^din[37]^din[38]^din[39]^din[40]^din[41]^din[42]^din[43]^din[44]^din[45]^din[46]^din[47]^din[48]^din[49]^din[50]^din[51]^din[52]^din[53]^din[54]^din[55]^din[56]; assign ecc_out[6] = din[57]^din[58]^din[59]^din[60]^din[61]^din[62]^din[63]; endmodule // rvecc_encode_64 module rvecc_decode_64 ( input en, input [63:0] din, input [6:0] ecc_in, output ecc_error ); logic [6:0] ecc_check; // Generate the ecc bits assign ecc_check[0] = ecc_in[0]^din[0]^din[1]^din[3]^din[4]^din[6]^din[8]^din[10]^din[11]^din[13]^din[15]^din[17]^din[19]^din[21]^din[23]^din[25]^din[26]^din[28]^din[30]^din[32]^din[34]^din[36]^din[38]^din[40]^din[42]^din[44]^din[46]^din[48]^din[50]^din[52]^din[54]^din[56]^din[57]^din[59]^din[61]^din[63]; assign ecc_check[1] = ecc_in[1]^din[0]^din[2]^din[3]^din[5]^din[6]^din[9]^din[10]^din[12]^din[13]^din[16]^din[17]^din[20]^din[21]^din[24]^din[25]^din[27]^din[28]^din[31]^din[32]^din[35]^din[36]^din[39]^din[40]^din[43]^din[44]^din[47]^din[48]^din[51]^din[52]^din[55]^din[56]^din[58]^din[59]^din[62]^din[63]; assign ecc_check[2] = ecc_in[2]^din[1]^din[2]^din[3]^din[7]^din[8]^din[9]^din[10]^din[14]^din[15]^din[16]^din[17]^din[22]^din[23]^din[24]^din[25]^din[29]^din[30]^din[31]^din[32]^din[37]^din[38]^din[39]^din[40]^din[45]^din[46]^din[47]^din[48]^din[53]^din[54]^din[55]^din[56]^din[60]^din[61]^din[62]^din[63]; assign ecc_check[3] = ecc_in[3]^din[4]^din[5]^din[6]^din[7]^din[8]^din[9]^din[10]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25]^din[33]^din[34]^din[35]^din[36]^din[37]^din[38]^din[39]^din[40]^din[49]^din[50]^din[51]^din[52]^din[53]^din[54]^din[55]^din[56]; assign ecc_check[4] = ecc_in[4]^din[11]^din[12]^din[13]^din[14]^din[15]^din[16]^din[17]^din[18]^din[19]^din[20]^din[21]^din[22]^din[23]^din[24]^din[25]^din[41]^din[42]^din[43]^din[44]^din[45]^din[46]^din[47]^din[48]^din[49]^din[50]^din[51]^din[52]^din[53]^din[54]^din[55]^din[56]; assign ecc_check[5] = ecc_in[5]^din[26]^din[27]^din[28]^din[29]^din[30]^din[31]^din[32]^din[33]^din[34]^din[35]^din[36]^din[37]^din[38]^din[39]^din[40]^din[41]^din[42]^din[43]^din[44]^din[45]^din[46]^din[47]^din[48]^din[49]^din[50]^din[51]^din[52]^din[53]^din[54]^din[55]^din[56]; assign ecc_check[6] = ecc_in[6]^din[57]^din[58]^din[59]^din[60]^din[61]^din[62]^din[63]; assign ecc_error = en & (ecc_check[6:0] != 0); // all errors in the sed_ded case will be recorded as DE endmodule // rvecc_decode_64 `ifndef TECH_SPECIFIC_EC_RV_ICG module `TEC_RV_ICG ( input logic SE, EN, CK, output Q ); logic en_ff; logic enable; assign enable = EN | SE; always @(CK, enable) begin if(!CK) en_ff = enable; end assign Q = CK & en_ff; endmodule `endif `ifndef RV_FPGA_OPTIMIZE module rvclkhdr ( input logic en, input logic clk, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ output logic l1clk ); logic SE; assign SE = 0; `ifdef TECH_SPECIFIC_EC_RV_ICG `USER_EC_RV_ICG clkhdr ( .*, .EN(en), .CK(clk), .Q(l1clk)); `else `TEC_RV_ICG clkhdr ( .*, .EN(en), .CK(clk), .Q(l1clk)); `endif endmodule // rvclkhdr `endif module rvoclkhdr ( input logic en, input logic clk, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ output logic l1clk ); logic SE; assign SE = 0; `ifdef RV_FPGA_OPTIMIZE assign l1clk = clk; `else `ifdef TECH_SPECIFIC_EC_RV_ICG `USER_EC_RV_ICG clkhdr ( .*, .EN(en), .CK(clk), .Q(l1clk)); `else `TEC_RV_ICG clkhdr ( .*, .EN(en), .CK(clk), .Q(l1clk)); `endif `endif endmodule ================================================ FILE: design/lib/el2_lib.sv ================================================ module el2_btb_tag_hash import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic [pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1] pc, output logic [pt.BTB_BTAG_SIZE-1:0] hash ); assign hash = {(pc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE+1] ^ pc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+1] ^ pc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1])}; endmodule module el2_btb_tag_hash_fold import el2_pkg::*; #( `include "el2_param.vh" )( input logic [pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1] pc, output logic [pt.BTB_BTAG_SIZE-1:0] hash ); assign hash = {( pc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE+1] ^ pc[pt.BTB_ADDR_HI+pt.BTB_BTAG_SIZE:pt.BTB_ADDR_HI+1])}; endmodule module el2_btb_addr_hash import el2_pkg::*; #( `include "el2_param.vh" )( input logic [pt.BTB_INDEX3_HI:pt.BTB_INDEX1_LO] pc, output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] hash ); if(pt.BTB_FOLD2_INDEX_HASH) begin : fold2 assign hash[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = pc[pt.BTB_INDEX1_HI:pt.BTB_INDEX1_LO] ^ pc[pt.BTB_INDEX3_HI:pt.BTB_INDEX3_LO]; end else begin assign hash[pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] = pc[pt.BTB_INDEX1_HI:pt.BTB_INDEX1_LO] ^ pc[pt.BTB_INDEX2_HI:pt.BTB_INDEX2_LO] ^ pc[pt.BTB_INDEX3_HI:pt.BTB_INDEX3_LO]; end endmodule module el2_btb_ghr_hash import el2_pkg::*; #( `include "el2_param.vh" )( input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] hashin, input logic [pt.BHT_GHR_SIZE-1:0] ghr, output logic [pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] hash ); // The hash function is too complex to write in verilog for all cases. // The config script generates the logic string based on the bp config. if(pt.BHT_GHR_HASH_1) begin : ghrhash_cfg1 assign hash[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] = { ghr[pt.BHT_GHR_SIZE-1:pt.BTB_INDEX1_HI-1], hashin[pt.BTB_INDEX1_HI:2]^ghr[pt.BTB_INDEX1_HI-2:0]}; end else begin : ghrhash_cfg2 assign hash[pt.BHT_ADDR_HI:pt.BHT_ADDR_LO] = { hashin[pt.BHT_GHR_SIZE+1:2]^ghr[pt.BHT_GHR_SIZE-1:0]}; end endmodule ================================================ FILE: design/lib/el2_mem_if.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // Copyright 2022 Microsoft Corporation // Copyright (c) 2023 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** interface el2_mem_if import el2_pkg::*; #( `include "el2_param.vh" ) (); ////////////////////////////////////////// // Clock logic clk; ////////////////////////////////////////// // ICCM logic [pt.ICCM_NUM_BANKS-1:0] iccm_clken; logic [pt.ICCM_NUM_BANKS-1:0] iccm_wren_bank; logic [pt.ICCM_NUM_BANKS-1:0][pt.ICCM_BITS-1:pt.ICCM_BANK_INDEX_LO] iccm_addr_bank; logic [pt.ICCM_NUM_BANKS-1:0][ 31:0] iccm_bank_wr_data; logic [pt.ICCM_NUM_BANKS-1:0][ pt.ICCM_ECC_WIDTH-1:0] iccm_bank_wr_ecc; logic [pt.ICCM_NUM_BANKS-1:0][ 31:0] iccm_bank_dout; logic [pt.ICCM_NUM_BANKS-1:0][ pt.ICCM_ECC_WIDTH-1:0] iccm_bank_ecc; ////////////////////////////////////////// // DCCM logic [pt.DCCM_NUM_BANKS-1:0] dccm_clken; logic [pt.DCCM_NUM_BANKS-1:0] dccm_wren_bank; logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_BITS-1:(pt.DCCM_BANK_BITS+2)] dccm_addr_bank; logic [pt.DCCM_NUM_BANKS-1:0][ pt.DCCM_DATA_WIDTH-1:0] dccm_wr_data_bank; logic [pt.DCCM_NUM_BANKS-1:0][ pt.DCCM_ECC_WIDTH-1:0] dccm_wr_ecc_bank; logic [pt.DCCM_NUM_BANKS-1:0][ pt.DCCM_DATA_WIDTH-1:0] dccm_bank_dout; logic [pt.DCCM_NUM_BANKS-1:0][ pt.DCCM_ECC_WIDTH-1:0] dccm_bank_ecc; ////////////////////////////////////////// // ICACHE DATA logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_WAYS-1:0] ic_b_sb_wren; logic [pt.ICACHE_BANKS_WAY-1:0][(71*pt.ICACHE_NUM_WAYS)-1:0] ic_b_sb_bit_en_vec; logic [pt.ICACHE_BANKS_WAY-1:0][(71*pt.ICACHE_NUM_WAYS)-1:0] wb_packeddout_pre; logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_sb_wr_data; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_INDEX_HI : pt.ICACHE_DATA_INDEX_LO] ic_rw_addr_bank_q; logic [pt.ICACHE_BANKS_WAY-1:0] ic_bank_way_clken_final; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_bank_way_clken_final_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][71-1:0] wb_dout_pre_up; ////////////////////////////////////////// // ICACHE TAG logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_clken_final; logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_wren_q; logic [(26*pt.ICACHE_NUM_WAYS)-1 :0] ic_tag_wren_biten_vec; logic [(26*pt.ICACHE_NUM_WAYS)-1 :0] ic_tag_data_raw_packed_pre; logic [25:0] ic_tag_wr_data; logic [pt.ICACHE_INDEX_HI: pt.ICACHE_TAG_INDEX_LO] ic_rw_addr_q; logic [pt.ICACHE_NUM_WAYS-1:0] [25:0] ic_tag_data_raw_pre; ////////////////////////////////////////// // MODPORTS modport veer_iccm( input clk, // ICCM output iccm_clken, iccm_wren_bank, iccm_addr_bank, iccm_bank_wr_data, iccm_bank_wr_ecc, input iccm_bank_dout, iccm_bank_ecc ); modport veer_dccm( input clk, // DCCM output dccm_clken, dccm_wren_bank, dccm_addr_bank, dccm_wr_data_bank, dccm_wr_ecc_bank, input dccm_bank_dout, dccm_bank_ecc ); modport veer_sram_src( output clk, // ICCM output iccm_clken, iccm_wren_bank, iccm_addr_bank, iccm_bank_wr_data, iccm_bank_wr_ecc, input iccm_bank_dout, iccm_bank_ecc, // DCCM output dccm_clken, dccm_wren_bank, dccm_addr_bank, dccm_wr_data_bank, dccm_wr_ecc_bank, input dccm_bank_dout, dccm_bank_ecc ); modport veer_sram_sink( input clk, // ICCM input iccm_clken, iccm_wren_bank, iccm_addr_bank, iccm_bank_wr_data, iccm_bank_wr_ecc, output iccm_bank_dout, iccm_bank_ecc, // DCCM input dccm_clken, dccm_wren_bank, dccm_addr_bank, dccm_wr_data_bank, dccm_wr_ecc_bank, output dccm_bank_dout, dccm_bank_ecc ); modport veer_icache_data( // data output ic_b_sb_wren, ic_b_sb_bit_en_vec, ic_sb_wr_data, ic_rw_addr_bank_q, ic_bank_way_clken_final, ic_bank_way_clken_final_up, input wb_packeddout_pre, wb_dout_pre_up ); modport veer_icache_tag( // tag output ic_tag_clken_final, ic_tag_wren_q, ic_tag_wren_biten_vec, ic_tag_wr_data, ic_rw_addr_q, input ic_tag_data_raw_packed_pre,ic_tag_data_raw_pre ); modport veer_icache_src( // cache uses the same clk as sram, we do not define clk port in this modport, // assuming the clk will be connected in sram_src // data output ic_b_sb_wren, ic_b_sb_bit_en_vec, ic_sb_wr_data, ic_rw_addr_bank_q, ic_bank_way_clken_final, ic_bank_way_clken_final_up, input wb_packeddout_pre, wb_dout_pre_up, // tag output ic_tag_clken_final, ic_tag_wren_q, ic_tag_wren_biten_vec, ic_tag_wr_data, ic_rw_addr_q, input ic_tag_data_raw_packed_pre,ic_tag_data_raw_pre ); endinterface ================================================ FILE: design/lib/el2_regfile_if.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** interface el2_regfile_if import el2_pkg::*; (); typedef struct packed { // General Purpose Registers logic [31:0] ra; // Return address logic [31:0] sp; // Stack pointer logic [31:0] fp; // Frame pointer logic [31:0] a0, a1; // Function arguments 0-1 / Return values 0-1 logic [31:0] a2, a3, a4, a5, a6, a7; // Function arguments 2-7 } el2_regfile_gpr_pkt_t; typedef struct packed { // Important registers chosen for exposure logic [31:0] pc, npc; // (Next) Program Counter logic [31:0] mstatus; // Machine status logic [31:0] mie; // Machine interrupt enable logic [31:0] mtvec; // Machine trap-handler base address logic [31:0] mscratch; // Scratch register for machine trap handlers logic [31:0] mepc; // Machine exception program counter logic [31:0] mcause; // Machine trap cause logic [31:0] mtval; // Machine bad address or instruction logic [31:0] mip; // Machine interrupt pending logic [31:0] mcyclel; // Machine cycle counter logic [31:0] mcycleh; // Machine cycle counter logic [31:0] minstretl; // Machine instructions-retired counter logic [31:0] minstreth; // Machine instructions-retired counter logic [31:0] mrac; // Region access control } el2_regfile_tlu_pkt_t; el2_regfile_gpr_pkt_t gpr; el2_regfile_tlu_pkt_t tlu; modport veer_gpr_rf(output gpr); modport veer_tlu_rf(output tlu); modport veer_rf_src(output gpr, output tlu); modport veer_rf_sink(input gpr, input tlu); endinterface ================================================ FILE: design/lib/mem_lib.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or it's affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. `define EL2_LOCAL_RAM_TEST_IO \ input logic WE, \ input logic ME, \ input logic CLK, \ input logic TEST1, \ input logic RME, \ input logic [3:0] RM, \ input logic LS, \ input logic DS, \ input logic SD, \ input logic TEST_RNM, \ input logic BC1, \ input logic BC2, \ output logic ROP `define EL2_RAM(depth, width) \ module ram_``depth``x``width( \ input logic [$clog2(depth)-1:0] ADR, \ input logic [(width-1):0] D, \ output logic [(width-1):0] Q, \ `EL2_LOCAL_RAM_TEST_IO \ ); \ reg [(width-1):0] ram_core [(depth-1):0]; \ `ifdef GTLSIM \ integer i; \ initial begin \ for (i=0; i put in the cam output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_m, // the tag of the external non block load output logic lsu_nonblock_load_inv_r, // invalidate signal for the cam entry for non block loads output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_r, // tag of the enrty which needs to be invalidated output logic lsu_nonblock_load_data_valid, // the non block is valid - sending information back to the cam output logic lsu_nonblock_load_data_error, // non block load has an error output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // the tag of the non block load sending the data/error output logic [31:0] lsu_nonblock_load_data, // Data of the non block load output logic lsu_pmu_load_external_m, // PMU : Bus loads output logic lsu_pmu_store_external_m, // PMU : Bus loads output logic lsu_pmu_misaligned_m, // PMU : misaligned output logic lsu_pmu_bus_trxn, // PMU : bus transaction output logic lsu_pmu_bus_misaligned, // PMU : misaligned access going to the bus output logic lsu_pmu_bus_error, // PMU : bus sending error back output logic lsu_pmu_bus_busy, // PMU : bus is not ready // Trigger signals input el2_trigger_pkt_t [3:0] trigger_pkt_any, // Trigger info from the decode output logic [3:0] lsu_trigger_match_m, // lsu trigger hit (one bit per trigger) // DCCM ports output logic dccm_wren, // DCCM write enable output logic dccm_rden, // DCCM read enable output logic [pt.DCCM_BITS-1:0] dccm_wr_addr_lo, // DCCM write address low bank output logic [pt.DCCM_BITS-1:0] dccm_wr_addr_hi, // DCCM write address hi bank output logic [pt.DCCM_BITS-1:0] dccm_rd_addr_lo, // DCCM read address low bank output logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi, // DCCM read address hi bank (hi and low same if aligned read) output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo, // DCCM write data for lo bank output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi, // DCCM write data for hi bank input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, // DCCM read data low bank input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // DCCM read data hi bank // PIC ports output logic picm_wren, // PIC memory write enable output logic picm_rden, // PIC memory read enable output logic picm_mken, // Need to read the mask for stores to determine which bits to write/forward output logic [31:0] picm_rdaddr, // address for pic read access output logic [31:0] picm_wraddr, // address for pic write access output logic [31:0] picm_wr_data, // PIC memory write data input logic [31:0] picm_rd_data, // PIC memory read/mask data // AXI Write Channels output logic lsu_axi_awvalid, input logic lsu_axi_awready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid, output logic [31:0] lsu_axi_awaddr, output logic [3:0] lsu_axi_awregion, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [7:0] lsu_axi_awlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_awsize, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [1:0] lsu_axi_awburst, output logic lsu_axi_awlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_awcache, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [2:0] lsu_axi_awprot, output logic [3:0] lsu_axi_awqos, /*pragma coverage on*/ output logic lsu_axi_wvalid, input logic lsu_axi_wready, output logic [63:0] lsu_axi_wdata, output logic [7:0] lsu_axi_wstrb, output logic lsu_axi_wlast, input logic lsu_axi_bvalid, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic lsu_axi_bready, /*pragma coverage on*/ input logic [1:0] lsu_axi_bresp, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid, // AXI Read Channels output logic lsu_axi_arvalid, input logic lsu_axi_arready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid, output logic [31:0] lsu_axi_araddr, output logic [3:0] lsu_axi_arregion, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [7:0] lsu_axi_arlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_arsize, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [1:0] lsu_axi_arburst, output logic lsu_axi_arlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_arcache, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [2:0] lsu_axi_arprot, output logic [3:0] lsu_axi_arqos, /*pragma coverage on*/ input logic lsu_axi_rvalid, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic lsu_axi_rready, /*pragma coverage on*/ input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid, input logic [63:0] lsu_axi_rdata, input logic [1:0] lsu_axi_rresp, input logic lsu_axi_rlast, input logic lsu_bus_clk_en, // external drives a clock_en to control bus ratio // DMA slave input logic dma_dccm_req, // DMA read/write to dccm input logic [2:0] dma_mem_tag, // DMA request tag input logic [31:0] dma_mem_addr, // DMA address input logic [2:0] dma_mem_sz, // DMA access size input logic dma_mem_write, // DMA access is a write input logic [63:0] dma_mem_wdata, // DMA write data output logic dccm_dma_rvalid, // lsu data valid for DMA dccm read output logic dccm_dma_ecc_error, // DMA load had ecc error output logic [2:0] dccm_dma_rtag, // DMA request tag output logic [63:0] dccm_dma_rdata, // lsu data for DMA dccm read output logic dccm_ready, // lsu ready for DMA access // DCCM ECC status output logic lsu_dccm_rd_ecc_single_err, output logic lsu_dccm_rd_ecc_double_err, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // scan mode /*pragma coverage on*/ input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic rst_l, // reset, active low output logic [31:0] lsu_pmp_addr_start, output logic [31:0] lsu_pmp_addr_end, input logic lsu_pmp_error_start, input logic lsu_pmp_error_end, output logic lsu_pmp_we, output logic lsu_pmp_re ); logic lsu_dccm_rden_m; logic lsu_dccm_rden_r; logic [31:0] store_data_m; logic [31:0] store_data_r; logic [31:0] store_data_hi_r, store_data_lo_r; logic [31:0] store_datafn_hi_r, store_datafn_lo_r; logic [31:0] sec_data_lo_m, sec_data_hi_m; logic [31:0] sec_data_lo_r, sec_data_hi_r; logic [31:0] lsu_ld_data_m; logic [31:0] dccm_rdata_hi_m, dccm_rdata_lo_m; logic [6:0] dccm_data_ecc_hi_m, dccm_data_ecc_lo_m; logic lsu_single_ecc_error_m; logic lsu_double_ecc_error_m; logic [31:0] lsu_ld_data_r; logic [31:0] lsu_ld_data_corr_r; logic [31:0] dccm_rdata_hi_r, dccm_rdata_lo_r; logic [6:0] dccm_data_ecc_hi_r, dccm_data_ecc_lo_r; logic single_ecc_error_hi_r, single_ecc_error_lo_r; logic lsu_single_ecc_error_r; logic lsu_double_ecc_error_r; logic ld_single_ecc_error_r, ld_single_ecc_error_r_ff; assign lsu_dccm_rd_ecc_single_err = lsu_single_ecc_error_r; assign lsu_dccm_rd_ecc_double_err = lsu_double_ecc_error_r; logic [31:0] picm_mask_data_m; logic [31:0] lsu_addr_d, lsu_addr_m, lsu_addr_r; logic [31:0] end_addr_d, end_addr_m, end_addr_r; assign lsu_pmp_addr_start = lsu_addr_d; assign lsu_pmp_addr_end = end_addr_d; el2_lsu_pkt_t lsu_pkt_d, lsu_pkt_m, lsu_pkt_r; logic lsu_i0_valid_d, lsu_i0_valid_m, lsu_i0_valid_r; assign lsu_pmp_we = lsu_pkt_d.store & lsu_pkt_d.valid; assign lsu_pmp_re = lsu_pkt_d.load & lsu_pkt_d.valid; // Store Buffer signals logic store_stbuf_reqvld_r; logic ldst_stbuf_reqvld_r; logic lsu_commit_r; logic lsu_exc_m; logic addr_in_dccm_d, addr_in_dccm_m, addr_in_dccm_r; logic addr_in_pic_d, addr_in_pic_m, addr_in_pic_r; logic ldst_dual_d, ldst_dual_m, ldst_dual_r; logic addr_external_m; logic stbuf_reqvld_any; logic stbuf_reqvld_flushed_any; logic [pt.LSU_SB_BITS-1:0] stbuf_addr_any; logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_data_any; logic [pt.DCCM_ECC_WIDTH-1:0] stbuf_ecc_any; logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r_ff, sec_data_hi_r_ff; logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_hi_r_ff, sec_data_ecc_lo_r_ff; logic lsu_cmpen_m; logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_m; logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_m; logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_m; logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_m; logic lsu_stbuf_commit_any; logic lsu_stbuf_empty_any; // This is for blocking loads logic lsu_stbuf_full_any; // Bus signals logic lsu_busreq_r; logic lsu_bus_buffer_pend_any; logic lsu_bus_buffer_empty_any; logic lsu_bus_buffer_full_any; logic lsu_busreq_m; logic [31:0] bus_read_data_m; logic flush_m_up, flush_r; logic is_sideeffects_m; logic [2:0] dma_mem_tag_d, dma_mem_tag_m; logic ldst_nodma_mtor; logic dma_dccm_wen, dma_pic_wen; logic [31:0] dma_dccm_wdata_lo, dma_dccm_wdata_hi; logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_lo, dma_dccm_wdata_ecc_hi; // Clocks logic lsu_busm_clken; logic lsu_bus_obuf_c1_clken; logic lsu_c1_m_clk, lsu_c1_r_clk; logic lsu_c2_m_clk, lsu_c2_r_clk; logic lsu_store_c1_m_clk, lsu_store_c1_r_clk; logic lsu_stbuf_c1_clk; logic lsu_bus_ibuf_c1_clk, lsu_bus_obuf_c1_clk, lsu_bus_buf_c1_clk; logic lsu_busm_clk; logic lsu_free_c2_clk; logic lsu_raw_fwd_lo_m, lsu_raw_fwd_hi_m; logic lsu_raw_fwd_lo_r, lsu_raw_fwd_hi_r; assign lsu_raw_fwd_lo_m = (|stbuf_fwdbyteen_lo_m[pt.DCCM_BYTE_WIDTH-1:0]); assign lsu_raw_fwd_hi_m = (|stbuf_fwdbyteen_hi_m[pt.DCCM_BYTE_WIDTH-1:0]); el2_lsu_lsc_ctl #(.pt(pt)) lsu_lsc_ctl (.*); // block stores in decode - for either bus or stbuf reasons assign lsu_store_stall_any = lsu_stbuf_full_any | lsu_bus_buffer_full_any | ld_single_ecc_error_r_ff; assign lsu_load_stall_any = lsu_bus_buffer_full_any | ld_single_ecc_error_r_ff; assign lsu_fastint_stall_any = ld_single_ecc_error_r; // Stall the fastint in decode-1 stage // Ready to accept dma trxns // There can't be any inpipe forwarding from non-dma packet to dma packet since they can be flushed so we can't have st in r when dma is in m assign dma_mem_tag_d[2:0] = dma_mem_tag[2:0]; assign ldst_nodma_mtor = (lsu_pkt_m.valid & ~lsu_pkt_m.dma & (addr_in_dccm_m | addr_in_pic_m) & lsu_pkt_m.store); assign dccm_ready = ~(dec_lsu_valid_raw_d | ldst_nodma_mtor | ld_single_ecc_error_r_ff); assign dma_dccm_wen = dma_dccm_req & dma_mem_write & addr_in_dccm_d & dma_mem_sz[1]; // Perform DMA writes only for word/dword assign dma_pic_wen = dma_dccm_req & dma_mem_write & addr_in_pic_d; assign {dma_dccm_wdata_hi[31:0], dma_dccm_wdata_lo[31:0]} = 64'(dma_mem_wdata[63:0] >> {dma_mem_addr[2:0], 3'b000}); // Shift the dma data to lower bits to make it consistent to lsu stores // Generate per cycle flush signals assign flush_m_up = dec_tlu_flush_lower_r; assign flush_r = dec_tlu_i0_kill_writeb_r; // lsu idle // lsu halt idle. This is used for entering the halt mode. Also, DMA accesses are allowed during fence. // Indicates non-idle if there is a instruction valid in d-r or read/write buffers are non-empty since they can come with error // Store buffer now have only non-dma dccm stores // stbuf_empty not needed since it has only dccm stores assign lsu_idle_any = ~((lsu_pkt_m.valid & ~lsu_pkt_m.dma) | (lsu_pkt_r.valid & ~lsu_pkt_r.dma)) & lsu_bus_buffer_empty_any; assign lsu_active = (lsu_pkt_m.valid | lsu_pkt_r.valid | ld_single_ecc_error_r_ff) | ~lsu_bus_buffer_empty_any; // This includes DMA. Used for gating top clock // Instantiate the store buffer assign store_stbuf_reqvld_r = lsu_pkt_r.valid & lsu_pkt_r.store & addr_in_dccm_r & ~flush_r & (~lsu_pkt_r.dma | ((lsu_pkt_r.by | lsu_pkt_r.half) & ~lsu_double_ecc_error_r)); // Disable Forwarding for now assign lsu_cmpen_m = lsu_pkt_m.valid & (lsu_pkt_m.load | lsu_pkt_m.store) & (addr_in_dccm_m | addr_in_pic_m); // Bus signals assign lsu_busreq_m = lsu_pkt_m.valid & ((lsu_pkt_m.load | lsu_pkt_m.store) & addr_external_m) & ~flush_m_up & ~lsu_exc_m & ~lsu_pkt_m.fast_int; // Dual signals assign ldst_dual_d = (lsu_addr_d[2] != end_addr_d[2]); assign ldst_dual_m = (lsu_addr_m[2] != end_addr_m[2]); assign ldst_dual_r = (lsu_addr_r[2] != end_addr_r[2]); // PMU signals assign lsu_pmu_misaligned_m = lsu_pkt_m.valid & ((lsu_pkt_m.half & lsu_addr_m[0]) | (lsu_pkt_m.word & (|lsu_addr_m[1:0]))); assign lsu_pmu_load_external_m = lsu_pkt_m.valid & lsu_pkt_m.load & addr_external_m; assign lsu_pmu_store_external_m = lsu_pkt_m.valid & lsu_pkt_m.store & addr_external_m; el2_lsu_dccm_ctl #(.pt(pt)) dccm_ctl ( .lsu_addr_d(lsu_addr_d[31:0]), .end_addr_d(end_addr_d[pt.DCCM_BITS-1:0]), .lsu_addr_m(lsu_addr_m[pt.DCCM_BITS-1:0]), .lsu_addr_r(lsu_addr_r[31:0]), .end_addr_m(end_addr_m[pt.DCCM_BITS-1:0]), .end_addr_r(end_addr_r[pt.DCCM_BITS-1:0]), .* ); el2_lsu_stbuf #(.pt(pt)) stbuf ( .lsu_addr_d(lsu_addr_d[pt.LSU_SB_BITS-1:0]), .end_addr_d(end_addr_d[pt.LSU_SB_BITS-1:0]), .* ); el2_lsu_ecc #(.pt(pt)) ecc ( .lsu_addr_r(lsu_addr_r[pt.DCCM_BITS-1:0]), .end_addr_r(end_addr_r[pt.DCCM_BITS-1:0]), .lsu_addr_m(lsu_addr_m[pt.DCCM_BITS-1:0]), .end_addr_m(end_addr_m[pt.DCCM_BITS-1:0]), .* ); el2_lsu_trigger #(.pt(pt)) trigger ( .store_data_m(store_data_m[31:0]), .* ); // Clk domain el2_lsu_clkdomain #(.pt(pt)) clkdomain (.*); // Bus interface el2_lsu_bus_intf #(.pt(pt)) bus_intf ( .lsu_addr_m(lsu_addr_m[31:0] & {32{addr_external_m & lsu_pkt_m.valid}}), .lsu_addr_r(lsu_addr_r[31:0] & {32{lsu_busreq_r}}), .end_addr_m(end_addr_m[31:0] & {32{addr_external_m & lsu_pkt_m.valid}}), .end_addr_r(end_addr_r[31:0] & {32{lsu_busreq_r}}), .store_data_r(store_data_r[31:0] & {32{lsu_busreq_r}}), .* ); //Flops rvdff #(3) dma_mem_tag_mff (.*, .din(dma_mem_tag_d[2:0]), .dout(dma_mem_tag_m[2:0]), .clk(lsu_c1_m_clk)); rvdff #(2) lsu_raw_fwd_r_ff (.*, .din({lsu_raw_fwd_hi_m, lsu_raw_fwd_lo_m}), .dout({lsu_raw_fwd_hi_r, lsu_raw_fwd_lo_r}), .clk(lsu_c2_r_clk)); `ifdef RV_ASSERT_ON logic [1:0] store_data_bypass_sel; assign store_data_bypass_sel[1:0] = {lsu_p.store_data_bypass_d, lsu_p.store_data_bypass_m}; property exception_no_lsu_flush; @(posedge clk) disable iff(~rst_l) lsu_lsc_ctl.lsu_error_pkt_m.exc_valid |-> ##[1:2] (flush_r ); endproperty assert_exception_no_lsu_flush: assert property (exception_no_lsu_flush) else $display("No flush within 2 cycles of exception"); // offset should be zero for fast interrupt property offset_0_fastint; @(posedge clk) disable iff(~rst_l) (lsu_p.valid & lsu_p.fast_int) |-> (dec_lsu_offset_d[11:0] == 12'b0); endproperty assert_offset_0_fastint: assert property (offset_0_fastint) else $display("dec_tlu_offset_d not zero for fast interrupt redirect"); // DMA req should assert dccm rden/wren property dmareq_dccm_wren_or_rden; @(posedge clk) disable iff(~rst_l) dma_dccm_req |-> (dccm_rden | dccm_wren | addr_in_pic_d); endproperty assert_dmareq_dccm_wren_or_rden: assert property(dmareq_dccm_wren_or_rden) else $display("dccm rden or wren not asserted during DMA request"); // fastint_stall should cause load/store stall next cycle property fastint_stall_imply_loadstore_stall; @(posedge clk) disable iff(~rst_l) (lsu_fastint_stall_any & (lsu_commit_r | lsu_pkt_r.dma)) |-> ##1 ((lsu_load_stall_any | lsu_store_stall_any) | ~ld_single_ecc_error_r_ff); endproperty assert_fastint_stall_imply_loadstore_stall: assert property (fastint_stall_imply_loadstore_stall) else $display("fastint_stall should be followed by lsu_load/store_stall_any"); // Single ECC error implies rfnpc flush property single_ecc_error_rfnpc_flush; @(posedge clk) disable iff(~rst_l) (lsu_error_pkt_r.single_ecc_error & lsu_pkt_r.load) |=> ~lsu_commit_r; endproperty assert_single_ecc_error_rfnpc_flush: assert property (single_ecc_error_rfnpc_flush) else $display("LSU commit next cycle after single ecc error"); `endif endmodule // el2_lsu ================================================ FILE: design/lsu/el2_lsu_addrcheck.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: Checks the memory map for the address // Comments: // //******************************************************************************** module el2_lsu_addrcheck import el2_pkg::*; #( `include "el2_param.vh" )( input logic lsu_c2_m_clk, // clock input logic rst_l, // reset input logic [31:0] start_addr_d, // start address for lsu input logic [31:0] end_addr_d, // end address for lsu input el2_lsu_pkt_t lsu_pkt_d, // packet in d input logic [31:0] dec_tlu_mrac_ff, // CSR read input logic [3:0] rs1_region_d, // address rs operand [31:28] input logic [31:0] rs1_d, // address rs operand output logic is_sideeffects_m, // is sideffects space output logic addr_in_dccm_d, // address in dccm output logic addr_in_pic_d, // address in pic output logic addr_external_d, // address in external output logic access_fault_d, // access fault output logic misaligned_fault_d, // misaligned output logic [3:0] exc_mscause_d, // mscause for access/misaligned faults output logic fir_dccm_access_error_d, // Fast interrupt dccm access error output logic fir_nondccm_access_error_d,// Fast interrupt dccm access error input logic lsu_pmp_error_start, input logic lsu_pmp_error_end, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // Scan mode /*pragma coverage on*/ ); logic non_dccm_access_ok; logic is_sideeffects_d, is_aligned_d; logic start_addr_in_dccm_d, end_addr_in_dccm_d; logic start_addr_in_dccm_region_d, end_addr_in_dccm_region_d; logic start_addr_in_pic_d, end_addr_in_pic_d; logic start_addr_in_pic_region_d, end_addr_in_pic_region_d; logic [4:0] csr_idx; logic addr_in_iccm; logic start_addr_dccm_or_pic; logic base_reg_dccm_or_pic; logic unmapped_access_fault_d, mpu_access_fault_d, picm_access_fault_d, regpred_access_fault_d; logic regcross_misaligned_fault_d, sideeffect_misaligned_fault_d; logic [3:0] access_fault_mscause_d; logic [3:0] misaligned_fault_mscause_d; if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable // Start address check rvrangecheck #(.CCM_SADR(pt.DCCM_SADR), .CCM_SIZE(pt.DCCM_SIZE)) start_addr_dccm_rangecheck ( .addr(start_addr_d[31:0]), .in_range(start_addr_in_dccm_d), .in_region(start_addr_in_dccm_region_d) ); // End address check rvrangecheck #(.CCM_SADR(pt.DCCM_SADR), .CCM_SIZE(pt.DCCM_SIZE)) end_addr_dccm_rangecheck ( .addr(end_addr_d[31:0]), .in_range(end_addr_in_dccm_d), .in_region(end_addr_in_dccm_region_d) ); end else begin: Gen_dccm_disable // block: Gen_dccm_enable assign start_addr_in_dccm_d = '0; assign start_addr_in_dccm_region_d = '0; assign end_addr_in_dccm_d = '0; assign end_addr_in_dccm_region_d = '0; end if (pt.ICCM_ENABLE == 1) begin : check_iccm assign addr_in_iccm = (start_addr_d[31:28] == pt.ICCM_REGION); end else begin assign addr_in_iccm = 1'b0; end // PIC memory check // Start address check rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR), .CCM_SIZE(pt.PIC_SIZE)) start_addr_pic_rangecheck ( .addr(start_addr_d[31:0]), .in_range(start_addr_in_pic_d), .in_region(start_addr_in_pic_region_d) ); // End address check rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR), .CCM_SIZE(pt.PIC_SIZE)) end_addr_pic_rangecheck ( .addr(end_addr_d[31:0]), .in_range(end_addr_in_pic_d), .in_region(end_addr_in_pic_region_d) ); assign start_addr_dccm_or_pic = start_addr_in_dccm_region_d | start_addr_in_pic_region_d; assign base_reg_dccm_or_pic = (|((rs1_region_d[3:0] == pt.DCCM_REGION) & pt.DCCM_ENABLE)) | (rs1_region_d[3:0] == pt.PIC_REGION); assign addr_in_dccm_d = (start_addr_in_dccm_d & end_addr_in_dccm_d); assign addr_in_pic_d = (start_addr_in_pic_d & end_addr_in_pic_d); assign addr_external_d = ~(start_addr_in_dccm_region_d | start_addr_in_pic_region_d); assign csr_idx[4:0] = {start_addr_d[31:28], 1'b1}; assign is_sideeffects_d = dec_tlu_mrac_ff[csr_idx] & ~(start_addr_in_dccm_region_d | start_addr_in_pic_region_d | addr_in_iccm) & lsu_pkt_d.valid & (lsu_pkt_d.store | lsu_pkt_d.load); //every region has the 2 LSB indicating ( 1: sideeffects/no_side effects, and 0: cacheable ). Ignored in internal regions assign is_aligned_d = (lsu_pkt_d.word & (start_addr_d[1:0] == 2'b0)) | (lsu_pkt_d.half & (start_addr_d[0] == 1'b0)) | lsu_pkt_d.by; logic ACCESS0_STARTOK; logic ACCESS1_STARTOK; logic ACCESS2_STARTOK; logic ACCESS3_STARTOK; logic ACCESS4_STARTOK; logic ACCESS5_STARTOK; logic ACCESS6_STARTOK; logic ACCESS7_STARTOK; logic ACCESS0_ENDOK; logic ACCESS1_ENDOK; logic ACCESS2_ENDOK; logic ACCESS3_ENDOK; logic ACCESS4_ENDOK; logic ACCESS5_ENDOK; logic ACCESS6_ENDOK; logic ACCESS7_ENDOK; assign ACCESS0_STARTOK = pt.DATA_ACCESS_ENABLE0 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK0)) == (pt.DATA_ACCESS_ADDR0 | pt.DATA_ACCESS_MASK0); assign ACCESS1_STARTOK = pt.DATA_ACCESS_ENABLE1 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK1)) == (pt.DATA_ACCESS_ADDR1 | pt.DATA_ACCESS_MASK1); assign ACCESS2_STARTOK = pt.DATA_ACCESS_ENABLE2 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK2)) == (pt.DATA_ACCESS_ADDR2 | pt.DATA_ACCESS_MASK2); assign ACCESS3_STARTOK = pt.DATA_ACCESS_ENABLE3 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK3)) == (pt.DATA_ACCESS_ADDR3 | pt.DATA_ACCESS_MASK3); assign ACCESS4_STARTOK = pt.DATA_ACCESS_ENABLE4 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK4)) == (pt.DATA_ACCESS_ADDR4 | pt.DATA_ACCESS_MASK4); assign ACCESS5_STARTOK = pt.DATA_ACCESS_ENABLE5 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK5)) == (pt.DATA_ACCESS_ADDR5 | pt.DATA_ACCESS_MASK5); assign ACCESS6_STARTOK = pt.DATA_ACCESS_ENABLE6 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK6)) == (pt.DATA_ACCESS_ADDR6 | pt.DATA_ACCESS_MASK6); assign ACCESS7_STARTOK = pt.DATA_ACCESS_ENABLE7 & ((start_addr_d[31:0] | pt.DATA_ACCESS_MASK7)) == (pt.DATA_ACCESS_ADDR7 | pt.DATA_ACCESS_MASK7); assign ACCESS0_ENDOK = pt.DATA_ACCESS_ENABLE0 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK0)) == (pt.DATA_ACCESS_ADDR0 | pt.DATA_ACCESS_MASK0); assign ACCESS1_ENDOK = pt.DATA_ACCESS_ENABLE1 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK1)) == (pt.DATA_ACCESS_ADDR1 | pt.DATA_ACCESS_MASK1); assign ACCESS2_ENDOK = pt.DATA_ACCESS_ENABLE2 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK2)) == (pt.DATA_ACCESS_ADDR2 | pt.DATA_ACCESS_MASK2); assign ACCESS3_ENDOK = pt.DATA_ACCESS_ENABLE3 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK3)) == (pt.DATA_ACCESS_ADDR3 | pt.DATA_ACCESS_MASK3); assign ACCESS4_ENDOK = pt.DATA_ACCESS_ENABLE4 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK4)) == (pt.DATA_ACCESS_ADDR4 | pt.DATA_ACCESS_MASK4); assign ACCESS5_ENDOK = pt.DATA_ACCESS_ENABLE5 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK5)) == (pt.DATA_ACCESS_ADDR5 | pt.DATA_ACCESS_MASK5); assign ACCESS6_ENDOK = pt.DATA_ACCESS_ENABLE6 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK6)) == (pt.DATA_ACCESS_ADDR6 | pt.DATA_ACCESS_MASK6); assign ACCESS7_ENDOK = pt.DATA_ACCESS_ENABLE7 & ((end_addr_d[31:0] | pt.DATA_ACCESS_MASK7)) == (pt.DATA_ACCESS_ADDR7 | pt.DATA_ACCESS_MASK7); if (pt.PMP_ENTRIES == 0) begin assign non_dccm_access_ok = (~(|{pt.DATA_ACCESS_ENABLE0,pt.DATA_ACCESS_ENABLE1,pt.DATA_ACCESS_ENABLE2,pt.DATA_ACCESS_ENABLE3,pt.DATA_ACCESS_ENABLE4,pt.DATA_ACCESS_ENABLE5,pt.DATA_ACCESS_ENABLE6,pt.DATA_ACCESS_ENABLE7})) | (( ACCESS0_STARTOK| ACCESS1_STARTOK| ACCESS2_STARTOK| ACCESS3_STARTOK| ACCESS4_STARTOK| ACCESS5_STARTOK| ACCESS6_STARTOK| ACCESS7_STARTOK) & ( ACCESS0_ENDOK| ACCESS1_ENDOK| ACCESS2_ENDOK| ACCESS3_ENDOK| ACCESS4_ENDOK| ACCESS5_ENDOK| ACCESS6_ENDOK| ACCESS7_ENDOK)); end // Access fault logic // 0. Unmapped local memory : Addr in dccm region but not in dccm offset OR Addr in picm region but not in picm offset OR DCCM -> PIC cross when DCCM/PIC in same region // 1. Uncorrectable (double bit) ECC error // 3. Address is not in a populated non-dccm region // 5. Region predication access fault: Base Address in DCCM/PIC and Final address in non-DCCM/non-PIC region or vice versa // 6. Ld/St access to picm are not word aligned or word size assign regpred_access_fault_d = (start_addr_dccm_or_pic ^ base_reg_dccm_or_pic); // 5. Region predication access fault: Base Address in DCCM/PIC and Final address in non-DCCM/non-PIC region or vice versa assign picm_access_fault_d = (addr_in_pic_d & ((start_addr_d[1:0] != 2'b0) | ~lsu_pkt_d.word)); // 6. Ld/St access to picm are not word aligned or word size if (pt.DCCM_ENABLE & (pt.DCCM_REGION == pt.PIC_REGION)) begin assign unmapped_access_fault_d = ((start_addr_in_dccm_region_d & ~(start_addr_in_dccm_d | start_addr_in_pic_d)) | // 0. Addr in dccm/pic region but not in dccm/pic offset (end_addr_in_dccm_region_d & ~(end_addr_in_dccm_d | end_addr_in_pic_d)) | // 0. Addr in dccm/pic region but not in dccm/pic offset (start_addr_in_dccm_d & end_addr_in_pic_d) | // 0. DCCM -> PIC cross when DCCM/PIC in same region (start_addr_in_pic_d & end_addr_in_dccm_d)); // 0. DCCM -> PIC cross when DCCM/PIC in same region if (pt.PMP_ENTRIES > 0) begin assign mpu_access_fault_d = (lsu_pmp_error_start | lsu_pmp_error_end); // X. Address is in blocked region end else begin assign mpu_access_fault_d = (~start_addr_in_dccm_region_d & ~non_dccm_access_ok); // 3. Address is not in a populated non-dccm region end end else begin assign unmapped_access_fault_d = ((start_addr_in_dccm_region_d & ~start_addr_in_dccm_d) | // 0. Addr in dccm region but not in dccm offset (end_addr_in_dccm_region_d & ~end_addr_in_dccm_d) | // 0. Addr in dccm region but not in dccm offset (start_addr_in_pic_region_d & ~start_addr_in_pic_d) | // 0. Addr in picm region but not in picm offset (end_addr_in_pic_region_d & ~end_addr_in_pic_d)); // 0. Addr in picm region but not in picm offset if (pt.PMP_ENTRIES > 0) begin assign mpu_access_fault_d = (lsu_pmp_error_start | lsu_pmp_error_end); // X. Address is in blocked region end else begin assign mpu_access_fault_d = (~start_addr_in_pic_region_d & ~start_addr_in_dccm_region_d & ~non_dccm_access_ok); // 3. Address is not in a populated non-dccm region end end assign access_fault_d = (unmapped_access_fault_d | mpu_access_fault_d | picm_access_fault_d | regpred_access_fault_d) & lsu_pkt_d.valid & ~lsu_pkt_d.dma; assign access_fault_mscause_d[3:0] = unmapped_access_fault_d ? 4'h2 : mpu_access_fault_d ? 4'h3 : regpred_access_fault_d ? 4'h5 : picm_access_fault_d ? 4'h6 : 4'h0; // Misaligned happens due to 2 reasons // 0. Region cross // 1. sideeffects access which are not aligned assign regcross_misaligned_fault_d = (start_addr_d[31:28] != end_addr_d[31:28]); assign sideeffect_misaligned_fault_d = (is_sideeffects_d & ~is_aligned_d); assign misaligned_fault_d = (regcross_misaligned_fault_d | (sideeffect_misaligned_fault_d & addr_external_d)) & lsu_pkt_d.valid & ~lsu_pkt_d.dma; assign misaligned_fault_mscause_d[3:0] = regcross_misaligned_fault_d ? 4'h2 : sideeffect_misaligned_fault_d ? 4'h1 : 4'h0; assign exc_mscause_d[3:0] = misaligned_fault_d ? misaligned_fault_mscause_d[3:0] : access_fault_mscause_d[3:0]; // Fast interrupt error logic assign fir_dccm_access_error_d = ((start_addr_in_dccm_region_d & ~start_addr_in_dccm_d) | (end_addr_in_dccm_region_d & ~end_addr_in_dccm_d)) & lsu_pkt_d.valid & lsu_pkt_d.fast_int; assign fir_nondccm_access_error_d = ~(start_addr_in_dccm_region_d & end_addr_in_dccm_region_d) & lsu_pkt_d.valid & lsu_pkt_d.fast_int; rvdff #(.WIDTH(1)) is_sideeffects_mff (.din(is_sideeffects_d), .dout(is_sideeffects_m), .clk(lsu_c2_m_clk), .*); endmodule // el2_lsu_addrcheck ================================================ FILE: design/lsu/el2_lsu_bus_buffer.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: lsu interface with interface queue // Comments: // //******************************************************************************** module el2_lsu_bus_buffer import el2_pkg::*; #( `include "el2_param.vh" )( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic clk_override, // Override non-functional clock gating input logic rst_l, // reset, active low // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // scan mode /*pragma coverage on*/ input logic dec_tlu_external_ldfwd_disable, // disable load to load forwarding for externals input logic dec_tlu_wb_coalescing_disable, // disable write buffer coalescing input logic dec_tlu_sideeffect_posted_disable, // Don't block the sideeffect load store to the bus input logic dec_tlu_force_halt, // various clocks needed for the bus reads and writes input logic lsu_bus_obuf_c1_clken, input logic lsu_busm_clken, input logic lsu_c2_r_clk, input logic lsu_bus_ibuf_c1_clk, input logic lsu_bus_obuf_c1_clk, input logic lsu_bus_buf_c1_clk, input logic lsu_free_c2_clk, input logic lsu_busm_clk, input logic dec_lsu_valid_raw_d, // Raw valid for address computation input el2_lsu_pkt_t lsu_pkt_m, // lsu packet flowing down the pipe input el2_lsu_pkt_t lsu_pkt_r, // lsu packet flowing down the pipe input logic [31:0] lsu_addr_m, // lsu address flowing down the pipe input logic [31:0] end_addr_m, // lsu address flowing down the pipe input logic [31:0] lsu_addr_r, // lsu address flowing down the pipe input logic [31:0] end_addr_r, // lsu address flowing down the pipe input logic [31:0] store_data_r, // store data flowing down the pipe input logic no_word_merge_r, // r store doesn't need to wait in ibuf since it will not coalesce input logic no_dword_merge_r, // r store doesn't need to wait in ibuf since it will not coalesce input logic lsu_busreq_m, // bus request is in m output logic lsu_busreq_r, // bus request is in r input logic ld_full_hit_m, // load can get all its byte from a write buffer entry input logic flush_m_up, // flush input logic flush_r, // flush input logic lsu_commit_r, // lsu instruction in r commits input logic is_sideeffects_r, // lsu attribute is side_effects input logic ldst_dual_d, // load/store is unaligned at 32 bit boundary input logic ldst_dual_m, // load/store is unaligned at 32 bit boundary input logic ldst_dual_r, // load/store is unaligned at 32 bit boundary input logic [7:0] ldst_byteen_ext_m, // HI and LO signals output logic lsu_bus_buffer_pend_any, // bus buffer has a pending bus entry output logic lsu_bus_buffer_full_any, // bus buffer is full output logic lsu_bus_buffer_empty_any, // bus buffer is empty output logic [3:0] ld_byte_hit_buf_lo, ld_byte_hit_buf_hi, // Byte enables for forwarding data output logic [31:0] ld_fwddata_buf_lo, ld_fwddata_buf_hi, // load forwarding data output logic lsu_imprecise_error_load_any, // imprecise load bus error output logic lsu_imprecise_error_store_any, // imprecise store bus error output logic [31:0] lsu_imprecise_error_addr_any, // address of the imprecise error // Non-blocking loads output logic lsu_nonblock_load_valid_m, // there is an external load -> put in the cam output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_m, // the tag of the external non block load output logic lsu_nonblock_load_inv_r, // invalidate signal for the cam entry for non block loads output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_r, // tag of the enrty which needs to be invalidated output logic lsu_nonblock_load_data_valid, // the non block is valid - sending information back to the cam output logic lsu_nonblock_load_data_error, // non block load has an error output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // the tag of the non block load sending the data/error output logic [31:0] lsu_nonblock_load_data, // Data of the non block load // PMU events output logic lsu_pmu_bus_trxn, output logic lsu_pmu_bus_misaligned, output logic lsu_pmu_bus_error, output logic lsu_pmu_bus_busy, // AXI Write Channels output logic lsu_axi_awvalid, input logic lsu_axi_awready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid, output logic [31:0] lsu_axi_awaddr, output logic [3:0] lsu_axi_awregion, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [7:0] lsu_axi_awlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_awsize, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [1:0] lsu_axi_awburst, output logic lsu_axi_awlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_awcache, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [2:0] lsu_axi_awprot, output logic [3:0] lsu_axi_awqos, /*pragma coverage on*/ output logic lsu_axi_wvalid, input logic lsu_axi_wready, output logic [63:0] lsu_axi_wdata, output logic [7:0] lsu_axi_wstrb, output logic lsu_axi_wlast, input logic lsu_axi_bvalid, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic lsu_axi_bready, /*pragma coverage on*/ input logic [1:0] lsu_axi_bresp, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid, // AXI Read Channels output logic lsu_axi_arvalid, input logic lsu_axi_arready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid, output logic [31:0] lsu_axi_araddr, output logic [3:0] lsu_axi_arregion, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [7:0] lsu_axi_arlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_arsize, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [1:0] lsu_axi_arburst, output logic lsu_axi_arlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_arcache, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [2:0] lsu_axi_arprot, output logic [3:0] lsu_axi_arqos, /*pragma coverage on*/ input logic lsu_axi_rvalid, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic lsu_axi_rready, /*pragma coverage on*/ input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid, input logic [63:0] lsu_axi_rdata, input logic [1:0] lsu_axi_rresp, input logic lsu_bus_clk_en, input logic lsu_bus_clk_en_q ); // For Ld: IDLE -> START_WAIT -> CMD -> RESP -> DONE_PARTIAL(?) -> DONE_WAIT(?) -> DONE -> IDLE // For St: IDLE -> START_WAIT -> CMD -> RESP(?) -> IDLE typedef enum logic [2:0] {IDLE=3'b000, START_WAIT=3'b001, CMD=3'b010, RESP=3'b011, DONE_PARTIAL=3'b100, DONE_WAIT=3'b101, DONE=3'b110} state_t; localparam DEPTH = pt.LSU_NUM_NBLOAD; localparam DEPTH_LOG2 = pt.LSU_NUM_NBLOAD_WIDTH; localparam TIMER = 8; // This can be only power of 2 localparam TIMER_MAX = TIMER - 1; // Maximum value of timer localparam TIMER_LOG2 = (TIMER < 2) ? 1 : $clog2(TIMER); logic [3:0] ldst_byteen_hi_m, ldst_byteen_lo_m; logic [DEPTH-1:0] ld_addr_hitvec_lo, ld_addr_hitvec_hi; logic [3:0][DEPTH-1:0] ld_byte_hitvec_lo, ld_byte_hitvec_hi; logic [3:0][DEPTH-1:0] ld_byte_hitvecfn_lo, ld_byte_hitvecfn_hi; logic ld_addr_ibuf_hit_lo, ld_addr_ibuf_hit_hi; logic [3:0] ld_byte_ibuf_hit_lo, ld_byte_ibuf_hit_hi; logic [3:0] ldst_byteen_r; logic [3:0] ldst_byteen_hi_r, ldst_byteen_lo_r; logic [31:0] store_data_hi_r, store_data_lo_r; logic is_aligned_r; // Aligned load/store logic ldst_samedw_r; logic lsu_nonblock_load_valid_r; logic [31:0] lsu_nonblock_load_data_hi, lsu_nonblock_load_data_lo, lsu_nonblock_data_unalgn; logic [1:0] lsu_nonblock_addr_offset; logic [1:0] lsu_nonblock_sz; logic lsu_nonblock_unsign; logic lsu_nonblock_load_data_ready; logic [DEPTH-1:0] CmdPtr0Dec, CmdPtr1Dec; logic [DEPTH-1:0] RspPtrDec; logic [DEPTH_LOG2-1:0] CmdPtr0, CmdPtr1; logic [DEPTH_LOG2-1:0] RspPtr; logic [DEPTH_LOG2-1:0] WrPtr0_m, WrPtr0_r; logic [DEPTH_LOG2-1:0] WrPtr1_m, WrPtr1_r; logic found_wrptr0, found_wrptr1, found_cmdptr0, found_cmdptr1; logic [3:0] buf_numvld_any, buf_numvld_wrcmd_any, buf_numvld_cmd_any, buf_numvld_pend_any; logic any_done_wait_state; logic bus_sideeffect_pend; logic bus_coalescing_disable; logic bus_addr_match_pending; logic bus_cmd_sent, bus_cmd_ready; logic bus_wcmd_sent, bus_wdata_sent; logic bus_rsp_read, bus_rsp_write; logic [pt.LSU_BUS_TAG-1:0] bus_rsp_read_tag, bus_rsp_write_tag; logic bus_rsp_read_error, bus_rsp_write_error; logic [63:0] bus_rsp_rdata; // Bus buffer signals state_t [DEPTH-1:0] buf_state; logic [DEPTH-1:0][1:0] buf_sz; logic [DEPTH-1:0][31:0] buf_addr; logic [DEPTH-1:0][3:0] buf_byteen; logic [DEPTH-1:0] buf_sideeffect; logic [DEPTH-1:0] buf_write; logic [DEPTH-1:0] buf_unsign; logic [DEPTH-1:0] buf_dual; logic [DEPTH-1:0] buf_samedw; logic [DEPTH-1:0] buf_nomerge; logic [DEPTH-1:0] buf_dualhi; logic [DEPTH-1:0][DEPTH_LOG2-1:0] buf_dualtag; logic [DEPTH-1:0] buf_ldfwd; logic [DEPTH-1:0][DEPTH_LOG2-1:0] buf_ldfwdtag; logic [DEPTH-1:0] buf_error; logic [DEPTH-1:0][31:0] buf_data; logic [DEPTH-1:0][DEPTH-1:0] buf_age, buf_age_younger; logic [DEPTH-1:0][DEPTH-1:0] buf_rspage, buf_rsp_pickage; state_t [DEPTH-1:0] buf_nxtstate; logic [DEPTH-1:0] buf_rst; logic [DEPTH-1:0] buf_state_en; logic [DEPTH-1:0] buf_cmd_state_bus_en; logic [DEPTH-1:0] buf_resp_state_bus_en; logic [DEPTH-1:0] buf_state_bus_en; logic [DEPTH-1:0] buf_dual_in; logic [DEPTH-1:0] buf_samedw_in; logic [DEPTH-1:0] buf_nomerge_in; logic [DEPTH-1:0] buf_sideeffect_in; logic [DEPTH-1:0] buf_unsign_in; logic [DEPTH-1:0][1:0] buf_sz_in; logic [DEPTH-1:0] buf_write_in; logic [DEPTH-1:0] buf_wr_en; logic [DEPTH-1:0] buf_dualhi_in; logic [DEPTH-1:0][DEPTH_LOG2-1:0] buf_dualtag_in; logic [DEPTH-1:0] buf_ldfwd_en; logic [DEPTH-1:0] buf_ldfwd_in; logic [DEPTH-1:0][DEPTH_LOG2-1:0] buf_ldfwdtag_in; logic [DEPTH-1:0][3:0] buf_byteen_in; logic [DEPTH-1:0][31:0] buf_addr_in; logic [DEPTH-1:0][31:0] buf_data_in; logic [DEPTH-1:0] buf_error_en; logic [DEPTH-1:0] buf_data_en; logic [DEPTH-1:0][DEPTH-1:0] buf_age_in; logic [DEPTH-1:0][DEPTH-1:0] buf_ageQ; logic [DEPTH-1:0][DEPTH-1:0] buf_rspage_set; logic [DEPTH-1:0][DEPTH-1:0] buf_rspage_in; logic [DEPTH-1:0][DEPTH-1:0] buf_rspageQ; // Input buffer signals logic ibuf_valid; logic ibuf_dual; logic ibuf_samedw; logic ibuf_nomerge; logic [DEPTH_LOG2-1:0] ibuf_tag; logic [DEPTH_LOG2-1:0] ibuf_dualtag; logic ibuf_sideeffect; logic ibuf_unsign; logic ibuf_write; logic [1:0] ibuf_sz; logic [3:0] ibuf_byteen; logic [31:0] ibuf_addr; logic [31:0] ibuf_data; logic [TIMER_LOG2-1:0] ibuf_timer; logic ibuf_byp; logic ibuf_wr_en; logic ibuf_rst; logic ibuf_force_drain; logic ibuf_drain_vld; logic [DEPTH-1:0] ibuf_drainvec_vld; logic [DEPTH_LOG2-1:0] ibuf_tag_in; logic [DEPTH_LOG2-1:0] ibuf_dualtag_in; logic [1:0] ibuf_sz_in; logic [31:0] ibuf_addr_in; logic [3:0] ibuf_byteen_in; logic [31:0] ibuf_data_in; logic [TIMER_LOG2-1:0] ibuf_timer_in; logic [3:0] ibuf_byteen_out; logic [31:0] ibuf_data_out; logic ibuf_merge_en, ibuf_merge_in; // Output buffer signals logic obuf_valid; logic obuf_write; logic obuf_nosend; logic obuf_rdrsp_pend; logic obuf_sideeffect; logic [31:0] obuf_addr; logic [63:0] obuf_data; logic [1:0] obuf_sz; logic [7:0] obuf_byteen; logic obuf_merge; logic obuf_cmd_done, obuf_data_done; logic [pt.LSU_BUS_TAG-1:0] obuf_tag0; logic [pt.LSU_BUS_TAG-1:0] obuf_tag1; logic [pt.LSU_BUS_TAG-1:0] obuf_rdrsp_tag; logic ibuf_buf_byp; logic obuf_force_wr_en; logic obuf_wr_wait; logic obuf_wr_en, obuf_wr_enQ; logic obuf_rst; logic obuf_write_in; logic obuf_nosend_in; logic obuf_rdrsp_pend_en; logic obuf_rdrsp_pend_in; logic obuf_sideeffect_in; logic obuf_aligned_in; logic [31:0] obuf_addr_in; logic [63:0] obuf_data_in; logic [1:0] obuf_sz_in; logic [7:0] obuf_byteen_in; logic obuf_merge_in; logic obuf_cmd_done_in, obuf_data_done_in; logic [pt.LSU_BUS_TAG-1:0] obuf_tag0_in; logic [pt.LSU_BUS_TAG-1:0] obuf_tag1_in; logic [pt.LSU_BUS_TAG-1:0] obuf_rdrsp_tag_in; logic obuf_merge_en; logic [TIMER_LOG2-1:0] obuf_wr_timer, obuf_wr_timer_in; logic [7:0] obuf_byteen0_in, obuf_byteen1_in; logic [63:0] obuf_data0_in, obuf_data1_in; logic lsu_axi_awvalid_q, lsu_axi_awready_q; logic lsu_axi_wvalid_q, lsu_axi_wready_q; logic lsu_axi_arvalid_q, lsu_axi_arready_q; logic lsu_axi_bvalid_q, lsu_axi_bready_q; logic lsu_axi_rvalid_q, lsu_axi_rready_q; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid_q, lsu_axi_rid_q; logic [1:0] lsu_axi_bresp_q, lsu_axi_rresp_q; logic [pt.LSU_BUS_TAG-1:0] lsu_imprecise_error_store_tag; logic [63:0] lsu_axi_rdata_q; //------------------------------------------------------------------------------ // Load forwarding logic start //------------------------------------------------------------------------------ // Function to do 8 to 3 bit encoding function automatic logic [2:0] f_Enc8to3; input logic [7:0] Dec_value; logic [2:0] Enc_value; Enc_value[0] = Dec_value[1] | Dec_value[3] | Dec_value[5] | Dec_value[7]; Enc_value[1] = Dec_value[2] | Dec_value[3] | Dec_value[6] | Dec_value[7]; Enc_value[2] = Dec_value[4] | Dec_value[5] | Dec_value[6] | Dec_value[7]; return Enc_value[2:0]; endfunction // f_Enc8to3 // Buffer hit logic for bus load forwarding assign ldst_byteen_hi_m[3:0] = ldst_byteen_ext_m[7:4]; assign ldst_byteen_lo_m[3:0] = ldst_byteen_ext_m[3:0]; for (genvar i=0; i 4'b0) & (obuf_wr_timer < TIMER_MAX)) ? (obuf_wr_timer + 1'b1) : obuf_wr_timer); assign obuf_force_wr_en = lsu_busreq_m & ~lsu_busreq_r & ~ibuf_valid & (buf_numvld_cmd_any[3:0] == 4'b1) & (lsu_addr_m[31:2] != buf_addr[CmdPtr0][31:2]); // Entry in m can't merge with entry going to obuf and there is no entry in between assign ibuf_buf_byp = ibuf_byp & (buf_numvld_pend_any[3:0] == 4'b0) & (~lsu_pkt_r.store | no_dword_merge_r); assign obuf_wr_en = ((ibuf_buf_byp & lsu_commit_r & ~(is_sideeffects_r & bus_sideeffect_pend)) | ((buf_state[CmdPtr0] == CMD) & found_cmdptr0 & ~buf_cmd_state_bus_en[CmdPtr0] & ~(buf_sideeffect[CmdPtr0] & bus_sideeffect_pend) & (~(buf_dual[CmdPtr0] & buf_samedw[CmdPtr0] & ~buf_write[CmdPtr0]) | found_cmdptr1 | buf_nomerge[CmdPtr0] | obuf_force_wr_en))) & (bus_cmd_ready | ~obuf_valid | obuf_nosend) & ~obuf_wr_wait & ~bus_addr_match_pending & lsu_bus_clk_en; assign obuf_rst = ((bus_cmd_sent | (obuf_valid & obuf_nosend)) & ~obuf_wr_en & lsu_bus_clk_en) | dec_tlu_force_halt; assign obuf_write_in = ibuf_buf_byp ? lsu_pkt_r.store : buf_write[CmdPtr0]; assign obuf_sideeffect_in = ibuf_buf_byp ? is_sideeffects_r : buf_sideeffect[CmdPtr0]; assign obuf_addr_in[31:0] = ibuf_buf_byp ? lsu_addr_r[31:0] : buf_addr[CmdPtr0]; assign obuf_sz_in[1:0] = ibuf_buf_byp ? {lsu_pkt_r.word, lsu_pkt_r.half} : buf_sz[CmdPtr0]; assign obuf_merge_in = obuf_merge_en; assign obuf_tag0_in[pt.LSU_BUS_TAG-1:0] = ibuf_buf_byp ? (pt.LSU_BUS_TAG)'(WrPtr0_r) : (pt.LSU_BUS_TAG)'(CmdPtr0); assign obuf_tag1_in[pt.LSU_BUS_TAG-1:0] = ibuf_buf_byp ? (pt.LSU_BUS_TAG)'(WrPtr1_r) : (pt.LSU_BUS_TAG)'(CmdPtr1); assign obuf_cmd_done_in = ~(obuf_wr_en | obuf_rst) & (obuf_cmd_done | bus_wcmd_sent); assign obuf_data_done_in = ~(obuf_wr_en | obuf_rst) & (obuf_data_done | bus_wdata_sent); assign obuf_aligned_in = ibuf_buf_byp ? is_aligned_r : ((obuf_sz_in[1:0] == 2'b0) | (obuf_sz_in[0] & ~obuf_addr_in[0]) | (obuf_sz_in[1] & ~(|obuf_addr_in[1:0]))); assign obuf_rdrsp_pend_in = ((~(obuf_wr_en & ~obuf_nosend_in) & obuf_rdrsp_pend & ~(bus_rsp_read & (bus_rsp_read_tag == obuf_rdrsp_tag))) | (bus_cmd_sent & ~obuf_write)) & ~dec_tlu_force_halt; assign obuf_rdrsp_pend_en = lsu_bus_clk_en | dec_tlu_force_halt; assign obuf_rdrsp_tag_in[pt.LSU_BUS_TAG-1:0] = (bus_cmd_sent & ~obuf_write) ? obuf_tag0[pt.LSU_BUS_TAG-1:0] : obuf_rdrsp_tag[pt.LSU_BUS_TAG-1:0]; // No ld to ld fwd for aligned assign obuf_nosend_in = (obuf_addr_in[31:3] == obuf_addr[31:3]) & obuf_aligned_in & ~obuf_sideeffect & ~obuf_write & ~obuf_write_in & ~dec_tlu_external_ldfwd_disable & ((obuf_valid & ~obuf_nosend) | (obuf_rdrsp_pend & ~(bus_rsp_read & (bus_rsp_read_tag == obuf_rdrsp_tag)))); assign obuf_byteen0_in[7:0] = ibuf_buf_byp ? (lsu_addr_r[2] ? {ldst_byteen_lo_r[3:0],4'b0} : {4'b0,ldst_byteen_lo_r[3:0]}) : (buf_addr[CmdPtr0][2] ? {buf_byteen[CmdPtr0],4'b0} : {4'b0,buf_byteen[CmdPtr0]}); assign obuf_byteen1_in[7:0] = ibuf_buf_byp ? (end_addr_r[2] ? {ldst_byteen_hi_r[3:0],4'b0} : {4'b0,ldst_byteen_hi_r[3:0]}) : (buf_addr[CmdPtr1][2] ? {buf_byteen[CmdPtr1],4'b0} : {4'b0,buf_byteen[CmdPtr1]}); assign obuf_data0_in[63:0] = ibuf_buf_byp ? (lsu_addr_r[2] ? {store_data_lo_r[31:0],32'b0} : {32'b0,store_data_lo_r[31:0]}) : (buf_addr[CmdPtr0][2] ? {buf_data[CmdPtr0],32'b0} : {32'b0,buf_data[CmdPtr0]}); assign obuf_data1_in[63:0] = ibuf_buf_byp ? (end_addr_r[2] ? {store_data_hi_r[31:0],32'b0} :{32'b0,store_data_hi_r[31:0]}) : (buf_addr[CmdPtr1][2] ? {buf_data[CmdPtr1],32'b0} : {32'b0,buf_data[CmdPtr1]}); for (genvar i=0 ;i<8; i++) begin assign obuf_byteen_in[i] = obuf_byteen0_in[i] | (obuf_merge_en & obuf_byteen1_in[i]); assign obuf_data_in[(8*i)+7:(8*i)] = (obuf_merge_en & obuf_byteen1_in[i]) ? obuf_data1_in[(8*i)+7:(8*i)] : obuf_data0_in[(8*i)+7:(8*i)]; end // No store obuf merging for AXI since all stores are sent non-posted. Can't track the second id right now assign obuf_merge_en = ((CmdPtr0 != CmdPtr1) & found_cmdptr0 & found_cmdptr1 & (buf_state[CmdPtr0] == CMD) & (buf_state[CmdPtr1] == CMD) & ~buf_cmd_state_bus_en[CmdPtr0] & ~buf_sideeffect[CmdPtr0] & (~buf_write[CmdPtr0] & buf_dual[CmdPtr0] & ~buf_dualhi[CmdPtr0] & buf_samedw[CmdPtr0])) | // CmdPtr0/CmdPtr1 are for same load which is within a DW (ibuf_buf_byp & ldst_samedw_r & ldst_dual_r); rvdff_fpga #(.WIDTH(1)) obuf_wren_ff (.din(obuf_wr_en), .dout(obuf_wr_enQ), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*); rvdffsc #(.WIDTH(1)) obuf_valid_ff (.din(1'b1), .dout(obuf_valid), .en(obuf_wr_en), .clear(obuf_rst), .clk(lsu_free_c2_clk), .*); rvdffs #(.WIDTH(1)) obuf_nosend_ff (.din(obuf_nosend_in), .dout(obuf_nosend), .en(obuf_wr_en), .clk(lsu_free_c2_clk), .*); rvdffs #(.WIDTH(1)) obuf_rdrsp_pend_ff(.din(obuf_rdrsp_pend_in), .dout(obuf_rdrsp_pend), .en(obuf_rdrsp_pend_en), .clk(lsu_free_c2_clk), .*); rvdff_fpga #(.WIDTH(1)) obuf_cmd_done_ff (.din(obuf_cmd_done_in), .dout(obuf_cmd_done), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(1)) obuf_data_done_ff (.din(obuf_data_done_in), .dout(obuf_data_done), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*); rvdff_fpga #(.WIDTH(pt.LSU_BUS_TAG)) obuf_rdrsp_tagff (.din(obuf_rdrsp_tag_in), .dout(obuf_rdrsp_tag), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(pt.LSU_BUS_TAG)) obuf_tag0ff (.din(obuf_tag0_in), .dout(obuf_tag0), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(pt.LSU_BUS_TAG)) obuf_tag1ff (.din(obuf_tag1_in), .dout(obuf_tag1), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(1)) obuf_mergeff (.din(obuf_merge_in), .dout(obuf_merge), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(1)) obuf_writeff (.din(obuf_write_in), .dout(obuf_write), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(1)) obuf_sideeffectff (.din(obuf_sideeffect_in), .dout(obuf_sideeffect), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(2)) obuf_szff (.din(obuf_sz_in[1:0]), .dout(obuf_sz), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*); rvdffs_fpga #(.WIDTH(8)) obuf_byteenff (.din(obuf_byteen_in[7:0]), .dout(obuf_byteen), .en(obuf_wr_en), .clk(lsu_bus_obuf_c1_clk), .clken(lsu_bus_obuf_c1_clken), .rawclk(clk), .*); rvdffe #(.WIDTH(32)) obuf_addrff (.din(obuf_addr_in[31:0]), .dout(obuf_addr), .en(obuf_wr_en), .*); rvdffe #(.WIDTH(64)) obuf_dataff (.din(obuf_data_in[63:0]), .dout(obuf_data), .en(obuf_wr_en), .*); rvdff_fpga #(.WIDTH(TIMER_LOG2)) obuf_timerff (.din(obuf_wr_timer_in), .dout(obuf_wr_timer), .clk(lsu_busm_clk), .clken(lsu_busm_clken), .rawclk(clk), .*); //------------------------------------------------------------------------------ // Output buffer logic ends here //------------------------------------------------------------------------------ // Find the entry to allocate and entry to send always_comb begin WrPtr0_m[DEPTH_LOG2-1:0] = '0; WrPtr1_m[DEPTH_LOG2-1:0] = '0; found_wrptr0 = '0; found_wrptr1 = '0; // Find first write pointer for (int i=0; i= (DEPTH-1)) : (buf_numvld_any[3:0] == DEPTH); assign lsu_bus_buffer_empty_any = ~(|buf_state[DEPTH-1:0]) & ~ibuf_valid & ~obuf_valid; // Non blocking ports assign lsu_nonblock_load_valid_m = lsu_busreq_m & lsu_pkt_m.valid & lsu_pkt_m.load & ~flush_m_up & ~ld_full_hit_m; assign lsu_nonblock_load_tag_m[DEPTH_LOG2-1:0] = WrPtr0_m[DEPTH_LOG2-1:0]; assign lsu_nonblock_load_inv_r = lsu_nonblock_load_valid_r & ~lsu_commit_r; assign lsu_nonblock_load_inv_tag_r[DEPTH_LOG2-1:0] = WrPtr0_r[DEPTH_LOG2-1:0]; // r tag needs to be accurate even if there is no invalidate always_comb begin lsu_nonblock_load_data_ready = '0; lsu_nonblock_load_data_error = '0; lsu_nonblock_load_data_tag[DEPTH_LOG2-1:0] = '0; lsu_nonblock_load_data_lo[31:0] = '0; lsu_nonblock_load_data_hi[31:0] = '0; for (int i=0; i> 8*lsu_nonblock_addr_offset[1:0]); assign lsu_nonblock_load_data_valid = lsu_nonblock_load_data_ready & ~lsu_nonblock_load_data_error; assign lsu_nonblock_load_data[31:0] = ({32{ lsu_nonblock_unsign & (lsu_nonblock_sz[1:0] == 2'b00)}} & {24'b0,lsu_nonblock_data_unalgn[7:0]}) | ({32{ lsu_nonblock_unsign & (lsu_nonblock_sz[1:0] == 2'b01)}} & {16'b0,lsu_nonblock_data_unalgn[15:0]}) | ({32{~lsu_nonblock_unsign & (lsu_nonblock_sz[1:0] == 2'b00)}} & {{24{lsu_nonblock_data_unalgn[7]}}, lsu_nonblock_data_unalgn[7:0]}) | ({32{~lsu_nonblock_unsign & (lsu_nonblock_sz[1:0] == 2'b01)}} & {{16{lsu_nonblock_data_unalgn[15]}},lsu_nonblock_data_unalgn[15:0]}) | ({32{(lsu_nonblock_sz[1:0] == 2'b10)}} & lsu_nonblock_data_unalgn[31:0]); // Determine if there is a pending return to sideeffect load/store always_comb begin bus_sideeffect_pend = obuf_valid & obuf_sideeffect & dec_tlu_sideeffect_posted_disable; for (int i=0; i put in the cam output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_m, // the tag of the external non block load output logic lsu_nonblock_load_inv_r, // invalidate signal for the cam entry for non block loads output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_r, // tag of the enrty which needs to be invalidated output logic lsu_nonblock_load_data_valid,// the non block is valid - sending information back to the cam output logic lsu_nonblock_load_data_error,// non block load has an error output logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // the tag of the non block load sending the data/error output logic [31:0] lsu_nonblock_load_data, // Data of the non block load // PMU events output logic lsu_pmu_bus_trxn, output logic lsu_pmu_bus_misaligned, output logic lsu_pmu_bus_error, output logic lsu_pmu_bus_busy, // AXI Write Channels output logic lsu_axi_awvalid, input logic lsu_axi_awready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid, output logic [31:0] lsu_axi_awaddr, output logic [3:0] lsu_axi_awregion, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [7:0] lsu_axi_awlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_awsize, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [1:0] lsu_axi_awburst, output logic lsu_axi_awlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_awcache, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [2:0] lsu_axi_awprot, output logic [3:0] lsu_axi_awqos, /*pragma coverage on*/ output logic lsu_axi_wvalid, input logic lsu_axi_wready, output logic [63:0] lsu_axi_wdata, output logic [7:0] lsu_axi_wstrb, output logic lsu_axi_wlast, input logic lsu_axi_bvalid, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic lsu_axi_bready, /*pragma coverage on*/ input logic [1:0] lsu_axi_bresp, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid, // AXI Read Channels output logic lsu_axi_arvalid, input logic lsu_axi_arready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid, output logic [31:0] lsu_axi_araddr, output logic [3:0] lsu_axi_arregion, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [7:0] lsu_axi_arlen, /*pragma coverage on*/ output logic [2:0] lsu_axi_arsize, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [1:0] lsu_axi_arburst, output logic lsu_axi_arlock, /*pragma coverage on*/ output logic [3:0] lsu_axi_arcache, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic [2:0] lsu_axi_arprot, output logic [3:0] lsu_axi_arqos, /*pragma coverage on*/ input logic lsu_axi_rvalid, /* exclude signals that are tied to constant value in el2_lsu_bus_buffer.sv */ /*pragma coverage off*/ output logic lsu_axi_rready, /*pragma coverage on*/ input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid, input logic [63:0] lsu_axi_rdata, input logic [1:0] lsu_axi_rresp, input logic lsu_bus_clk_en ); logic lsu_bus_clk_en_q; logic [3:0] ldst_byteen_m, ldst_byteen_r; logic [7:0] ldst_byteen_ext_m, ldst_byteen_ext_r; logic [3:0] ldst_byteen_hi_m, ldst_byteen_hi_r; logic [3:0] ldst_byteen_lo_m, ldst_byteen_lo_r; logic is_sideeffects_r; logic [63:0] store_data_ext_r; logic [31:0] store_data_hi_r; logic [31:0] store_data_lo_r; logic addr_match_dw_lo_r_m; logic addr_match_word_lo_r_m; logic no_word_merge_r, no_dword_merge_r; logic ld_addr_rhit_lo_lo, ld_addr_rhit_hi_lo, ld_addr_rhit_lo_hi, ld_addr_rhit_hi_hi; logic [3:0] ld_byte_rhit_lo_lo, ld_byte_rhit_hi_lo, ld_byte_rhit_lo_hi, ld_byte_rhit_hi_hi; logic [3:0] ld_byte_hit_lo, ld_byte_rhit_lo; logic [3:0] ld_byte_hit_hi, ld_byte_rhit_hi; logic [31:0] ld_fwddata_rpipe_lo; logic [31:0] ld_fwddata_rpipe_hi; logic [3:0] ld_byte_hit_buf_lo, ld_byte_hit_buf_hi; logic [31:0] ld_fwddata_buf_lo, ld_fwddata_buf_hi; logic [63:0] ld_fwddata_lo, ld_fwddata_hi; logic [63:0] ld_fwddata_m; logic ld_full_hit_hi_m, ld_full_hit_lo_m; logic ld_full_hit_m; assign ldst_byteen_m[3:0] = ({4{lsu_pkt_m.by}} & 4'b0001) | ({4{lsu_pkt_m.half}} & 4'b0011) | ({4{lsu_pkt_m.word}} & 4'b1111); // Read/Write Buffer el2_lsu_bus_buffer #(.pt(pt)) bus_buffer ( .* ); // Logic to determine if dc5 store can be coalesced or not with younger stores. Bypass ibuf if cannot colaesced assign addr_match_dw_lo_r_m = (lsu_addr_r[31:3] == lsu_addr_m[31:3]); assign addr_match_word_lo_r_m = addr_match_dw_lo_r_m & ~(lsu_addr_r[2]^lsu_addr_m[2]); assign no_word_merge_r = lsu_busreq_r & ~ldst_dual_r & lsu_busreq_m & (lsu_pkt_m.load | ~addr_match_word_lo_r_m); assign no_dword_merge_r = lsu_busreq_r & ~ldst_dual_r & lsu_busreq_m & (lsu_pkt_m.load | ~addr_match_dw_lo_r_m); // Create Hi/Lo signals assign ldst_byteen_ext_m[7:0] = {4'b0,ldst_byteen_m[3:0]} << lsu_addr_m[1:0]; assign ldst_byteen_ext_r[7:0] = {4'b0,ldst_byteen_r[3:0]} << lsu_addr_r[1:0]; assign store_data_ext_r[63:0] = {32'b0,store_data_r[31:0]} << {lsu_addr_r[1:0],3'b0}; assign ldst_byteen_hi_m[3:0] = ldst_byteen_ext_m[7:4]; assign ldst_byteen_lo_m[3:0] = ldst_byteen_ext_m[3:0]; assign ldst_byteen_hi_r[3:0] = ldst_byteen_ext_r[7:4]; assign ldst_byteen_lo_r[3:0] = ldst_byteen_ext_r[3:0]; assign store_data_hi_r[31:0] = store_data_ext_r[63:32]; assign store_data_lo_r[31:0] = store_data_ext_r[31:0]; assign ld_addr_rhit_lo_lo = (lsu_addr_m[31:2] == lsu_addr_r[31:2]) & lsu_pkt_r.valid & lsu_pkt_r.store & lsu_busreq_m & lsu_busreq_r; assign ld_addr_rhit_lo_hi = (end_addr_m[31:2] == lsu_addr_r[31:2]) & lsu_pkt_r.valid & lsu_pkt_r.store & lsu_busreq_m & lsu_busreq_r; assign ld_addr_rhit_hi_lo = (lsu_addr_m[31:2] == end_addr_r[31:2]) & lsu_pkt_r.valid & lsu_pkt_r.store & lsu_busreq_m & lsu_busreq_r; assign ld_addr_rhit_hi_hi = (end_addr_m[31:2] == end_addr_r[31:2]) & lsu_pkt_r.valid & lsu_pkt_r.store & lsu_busreq_m & lsu_busreq_r; for (genvar i=0; i<4; i++) begin: GenBusBufFwd assign ld_byte_rhit_lo_lo[i] = ld_addr_rhit_lo_lo & ldst_byteen_lo_r[i] & ldst_byteen_lo_m[i]; assign ld_byte_rhit_lo_hi[i] = ld_addr_rhit_lo_hi & ldst_byteen_lo_r[i] & ldst_byteen_hi_m[i]; assign ld_byte_rhit_hi_lo[i] = ld_addr_rhit_hi_lo & ldst_byteen_hi_r[i] & ldst_byteen_lo_m[i]; assign ld_byte_rhit_hi_hi[i] = ld_addr_rhit_hi_hi & ldst_byteen_hi_r[i] & ldst_byteen_hi_m[i]; assign ld_byte_hit_lo[i] = ld_byte_rhit_lo_lo[i] | ld_byte_rhit_hi_lo[i] | ld_byte_hit_buf_lo[i]; assign ld_byte_hit_hi[i] = ld_byte_rhit_lo_hi[i] | ld_byte_rhit_hi_hi[i] | ld_byte_hit_buf_hi[i]; assign ld_byte_rhit_lo[i] = ld_byte_rhit_lo_lo[i] | ld_byte_rhit_hi_lo[i]; assign ld_byte_rhit_hi[i] = ld_byte_rhit_lo_hi[i] | ld_byte_rhit_hi_hi[i]; assign ld_fwddata_rpipe_lo[(8*i)+7:(8*i)] = ({8{ld_byte_rhit_lo_lo[i]}} & store_data_lo_r[(8*i)+7:(8*i)]) | ({8{ld_byte_rhit_hi_lo[i]}} & store_data_hi_r[(8*i)+7:(8*i)]); assign ld_fwddata_rpipe_hi[(8*i)+7:(8*i)] = ({8{ld_byte_rhit_lo_hi[i]}} & store_data_lo_r[(8*i)+7:(8*i)]) | ({8{ld_byte_rhit_hi_hi[i]}} & store_data_hi_r[(8*i)+7:(8*i)]); // Final muxing between m/r assign ld_fwddata_lo[(8*i)+7:(8*i)] = ld_byte_rhit_lo[i] ? ld_fwddata_rpipe_lo[(8*i)+7:(8*i)] : ld_fwddata_buf_lo[(8*i)+7:(8*i)]; assign ld_fwddata_hi[(8*i)+7:(8*i)] = ld_byte_rhit_hi[i] ? ld_fwddata_rpipe_hi[(8*i)+7:(8*i)] : ld_fwddata_buf_hi[(8*i)+7:(8*i)]; end always_comb begin ld_full_hit_lo_m = 1'b1; ld_full_hit_hi_m = 1'b1; for (int i=0; i<4; i++) begin ld_full_hit_lo_m &= (ld_byte_hit_lo[i] | ~ldst_byteen_lo_m[i]); ld_full_hit_hi_m &= (ld_byte_hit_hi[i] | ~ldst_byteen_hi_m[i]); end end // This will be high if all the bytes of load hit the stores in pipe/write buffer (m/r/wrbuf) assign ld_full_hit_m = ld_full_hit_lo_m & ld_full_hit_hi_m & lsu_busreq_m & lsu_pkt_m.load & ~is_sideeffects_m; assign ld_fwddata_m[63:0] = 64'({ld_fwddata_hi[31:0], ld_fwddata_lo[31:0]} >> (8*lsu_addr_m[1:0])); assign bus_read_data_m[31:0] = ld_fwddata_m[31:0]; // Fifo flops rvdff #(.WIDTH(1)) clken_ff (.din(lsu_bus_clk_en), .dout(lsu_bus_clk_en_q), .clk(active_clk), .*); rvdff #(.WIDTH(1)) is_sideeffects_rff (.din(is_sideeffects_m), .dout(is_sideeffects_r), .clk(lsu_c1_r_clk), .*); rvdff #(4) lsu_byten_rff (.*, .din(ldst_byteen_m[3:0]), .dout(ldst_byteen_r[3:0]), .clk(lsu_c1_r_clk)); `ifdef RV_ASSERT_ON // Assertion to check AXI write address is aligned to size property lsu_axi_awaddr_aligned; @(posedge lsu_busm_clk) disable iff(~rst_l) lsu_axi_awvalid |-> ((lsu_axi_awsize[2:0] == 3'h0) | ((lsu_axi_awsize[2:0] == 3'h1) & (lsu_axi_awaddr[0] == 1'b0)) | ((lsu_axi_awsize[2:0] == 3'h2) & (lsu_axi_awaddr[1:0] == 2'b0)) | ((lsu_axi_awsize[2:0] == 3'h3) & (lsu_axi_awaddr[2:0] == 3'b0))); endproperty assert_lsu_axi_awaddr_aligned: assert property (lsu_axi_awaddr_aligned) else $display("Assertion lsu_axi_awaddr_aligned failed: lsu_axi_awvalid=1'b%b, lsu_axi_awsize=3'h%h, lsu_axi_awaddr=32'h%h",lsu_axi_awvalid, lsu_axi_awsize[2:0], lsu_axi_awaddr[31:0]); // Assertion to check awvalid stays stable during entire bus clock // Assertion to check AXI read address is aligned to size property lsu_axi_araddr_aligned; @(posedge lsu_busm_clk) disable iff(~rst_l) lsu_axi_arvalid |-> ((lsu_axi_arsize[2:0] == 3'h0) | ((lsu_axi_arsize[2:0] == 3'h1) & (lsu_axi_araddr[0] == 1'b0)) | ((lsu_axi_arsize[2:0] == 3'h2) & (lsu_axi_araddr[1:0] == 2'b0)) | ((lsu_axi_arsize[2:0] == 3'h3) & (lsu_axi_araddr[2:0] == 3'b0))); endproperty assert_lsu_axi_araddr_aligned: assert property (lsu_axi_araddr_aligned) else $display("Assertion lsu_axi_araddr_aligned failed: lsu_axi_awvalid=1'b%b, lsu_axi_awsize=3'h%h, lsu_axi_araddr=32'h%h",lsu_axi_awvalid, lsu_axi_awsize[2:0], lsu_axi_araddr[31:0]); // Assertion to check awvalid stays stable during entire bus clock property lsu_axi_awvalid_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_awvalid != $past(lsu_axi_awvalid)) |-> ($past(lsu_bus_clk_en) | dec_tlu_force_halt); endproperty assert_lsu_axi_awvalid_stable: assert property (lsu_axi_awvalid_stable) else $display("LSU AXI awvalid changed in middle of bus clock"); // Assertion to check awid stays stable during entire bus clock property lsu_axi_awid_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_awvalid & (lsu_axi_awid[pt.LSU_BUS_TAG-1:0] != $past(lsu_axi_awid[pt.LSU_BUS_TAG-1:0]))) |-> $past(lsu_bus_clk_en); endproperty assert_lsu_axi_awid_stable: assert property (lsu_axi_awid_stable) else $display("LSU AXI awid changed in middle of bus clock"); // Assertion to check awaddr stays stable during entire bus clock property lsu_axi_awaddr_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_awvalid & (lsu_axi_awaddr[31:0] != $past(lsu_axi_awaddr[31:0]))) |-> $past(lsu_bus_clk_en); endproperty assert_lsu_axi_awaddr_stable: assert property (lsu_axi_awaddr_stable) else $display("LSU AXI awaddr changed in middle of bus clock"); // Assertion to check awsize stays stable during entire bus clock property lsu_axi_awsize_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_awvalid & (lsu_axi_awsize[2:0] != $past(lsu_axi_awsize[2:0]))) |-> $past(lsu_bus_clk_en); endproperty assert_lsu_axi_awsize_stable: assert property (lsu_axi_awsize_stable) else $display("LSU AXI awsize changed in middle of bus clock"); // Assertion to check wstrb stays stable during entire bus clock property lsu_axi_wstrb_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_wvalid & (lsu_axi_wstrb[7:0] != $past(lsu_axi_wstrb[7:0]))) |-> $past(lsu_bus_clk_en); endproperty assert_lsu_axi_wstrb_stable: assert property (lsu_axi_wstrb_stable) else $display("LSU AXI wstrb changed in middle of bus clock"); // Assertion to check wdata stays stable during entire bus clock property lsu_axi_wdata_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_wvalid & (lsu_axi_wdata[63:0] != $past(lsu_axi_wdata[63:0]))) |-> $past(lsu_bus_clk_en); endproperty assert_lsu_axi_wdata_stable: assert property (lsu_axi_wdata_stable) else $display("LSU AXI wdata changed in middle of bus clock"); // Assertion to check awvalid stays stable during entire bus clock property lsu_axi_arvalid_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_arvalid != $past(lsu_axi_arvalid)) |-> ($past(lsu_bus_clk_en) | dec_tlu_force_halt); endproperty assert_lsu_axi_arvalid_stable: assert property (lsu_axi_arvalid_stable) else $display("LSU AXI awvalid changed in middle of bus clock"); // Assertion to check awid stays stable during entire bus clock property lsu_axi_arid_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_arvalid & (lsu_axi_arid[pt.LSU_BUS_TAG-1:0] != $past(lsu_axi_arid[pt.LSU_BUS_TAG-1:0]))) |-> $past(lsu_bus_clk_en); endproperty assert_lsu_axi_arid_stable: assert property (lsu_axi_arid_stable) else $display("LSU AXI awid changed in middle of bus clock"); // Assertion to check awaddr stays stable during entire bus clock property lsu_axi_araddr_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_arvalid & (lsu_axi_araddr[31:0] != $past(lsu_axi_araddr[31:0]))) |-> $past(lsu_bus_clk_en); endproperty assert_lsu_axi_araddr_stable: assert property (lsu_axi_araddr_stable) else $display("LSU AXI awaddr changed in middle of bus clock"); // Assertion to check awsize stays stable during entire bus clock property lsu_axi_arsize_stable; @(posedge clk) disable iff(~rst_l) (lsu_axi_awvalid & (lsu_axi_arsize[2:0] != $past(lsu_axi_arsize[2:0]))) |-> $past(lsu_bus_clk_en); endproperty assert_lsu_axi_arsize_stable: assert property (lsu_axi_arsize_stable) else $display("LSU AXI awsize changed in middle of bus clock"); `endif endmodule // el2_lsu_bus_intf ================================================ FILE: design/lsu/el2_lsu_clkdomain.sv ================================================ // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: Clock Generation Block // Comments: All the clocks are generate here // // //******************************************************************************** module el2_lsu_clkdomain import el2_pkg::*; #( `include "el2_param.vh" )( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic rst_l, // reset, active low input logic dec_tlu_force_halt, // This will be high till TLU goes to debug halt // Inputs input logic clk_override, // chciken bit to turn off clock gating input logic dma_dccm_req, // dma is active input logic ldst_stbuf_reqvld_r, // allocating in to the store queue input logic stbuf_reqvld_any, // stbuf is draining input logic stbuf_reqvld_flushed_any, // instruction going to stbuf is flushed input logic lsu_busreq_r, // busreq in r input logic lsu_bus_buffer_pend_any, // bus buffer has a pending bus entry input logic lsu_bus_buffer_empty_any, // external bus buffer is empty input logic lsu_stbuf_empty_any, // stbuf is empty input logic lsu_bus_clk_en, // bus clock enable input el2_lsu_pkt_t lsu_p, // lsu packet in decode input el2_lsu_pkt_t lsu_pkt_d, // lsu packet in d input el2_lsu_pkt_t lsu_pkt_m, // lsu packet in m input el2_lsu_pkt_t lsu_pkt_r, // lsu packet in r // Outputs output logic lsu_bus_obuf_c1_clken, // obuf clock enable output logic lsu_busm_clken, // bus clock enable output logic lsu_c1_m_clk, // m pipe single pulse clock output logic lsu_c1_r_clk, // r pipe single pulse clock output logic lsu_c2_m_clk, // m pipe double pulse clock output logic lsu_c2_r_clk, // r pipe double pulse clock output logic lsu_store_c1_m_clk, // store in m output logic lsu_store_c1_r_clk, // store in r output logic lsu_stbuf_c1_clk, output logic lsu_bus_obuf_c1_clk, // ibuf clock output logic lsu_bus_ibuf_c1_clk, // ibuf clock output logic lsu_bus_buf_c1_clk, // ibuf clock output logic lsu_busm_clk, // bus clock output logic lsu_free_c2_clk, // free double pulse clock // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // Scan mode /*pragma coverage on*/ ); logic lsu_c1_m_clken, lsu_c1_r_clken; logic lsu_c2_m_clken, lsu_c2_r_clken; logic lsu_c1_m_clken_q, lsu_c1_r_clken_q; logic lsu_store_c1_m_clken, lsu_store_c1_r_clken; logic lsu_stbuf_c1_clken; logic lsu_bus_ibuf_c1_clken, lsu_bus_buf_c1_clken; logic lsu_free_c1_clken, lsu_free_c1_clken_q, lsu_free_c2_clken; //------------------------------------------------------------------------------------------- // Clock Enable logic //------------------------------------------------------------------------------------------- assign lsu_c1_m_clken = lsu_p.valid | dma_dccm_req | clk_override; assign lsu_c1_r_clken = lsu_pkt_m.valid | lsu_c1_m_clken_q | clk_override; assign lsu_c2_m_clken = lsu_c1_m_clken | lsu_c1_m_clken_q | clk_override; assign lsu_c2_r_clken = lsu_c1_r_clken | lsu_c1_r_clken_q | clk_override; assign lsu_store_c1_m_clken = ((lsu_c1_m_clken & lsu_pkt_d.store) | clk_override) ; assign lsu_store_c1_r_clken = ((lsu_c1_r_clken & lsu_pkt_m.store) | clk_override) ; assign lsu_stbuf_c1_clken = ldst_stbuf_reqvld_r | stbuf_reqvld_any | stbuf_reqvld_flushed_any | clk_override; assign lsu_bus_ibuf_c1_clken = lsu_busreq_r | clk_override; assign lsu_bus_obuf_c1_clken = (lsu_bus_buffer_pend_any | lsu_busreq_r | clk_override) & lsu_bus_clk_en; assign lsu_bus_buf_c1_clken = ~lsu_bus_buffer_empty_any | lsu_busreq_r | dec_tlu_force_halt | clk_override; assign lsu_free_c1_clken = (lsu_p.valid | lsu_pkt_d.valid | lsu_pkt_m.valid | lsu_pkt_r.valid) | ~lsu_bus_buffer_empty_any | ~lsu_stbuf_empty_any | clk_override; assign lsu_free_c2_clken = lsu_free_c1_clken | lsu_free_c1_clken_q | clk_override; // Flops rvdff #(1) lsu_free_c1_clkenff (.din(lsu_free_c1_clken), .dout(lsu_free_c1_clken_q), .clk(active_clk), .*); rvdff #(1) lsu_c1_m_clkenff (.din(lsu_c1_m_clken), .dout(lsu_c1_m_clken_q), .clk(lsu_free_c2_clk), .*); rvdff #(1) lsu_c1_r_clkenff (.din(lsu_c1_r_clken), .dout(lsu_c1_r_clken_q), .clk(lsu_free_c2_clk), .*); // Clock Headers rvoclkhdr lsu_c1m_cgc ( .en(lsu_c1_m_clken), .l1clk(lsu_c1_m_clk), .* ); rvoclkhdr lsu_c1r_cgc ( .en(lsu_c1_r_clken), .l1clk(lsu_c1_r_clk), .* ); rvoclkhdr lsu_c2m_cgc ( .en(lsu_c2_m_clken), .l1clk(lsu_c2_m_clk), .* ); rvoclkhdr lsu_c2r_cgc ( .en(lsu_c2_r_clken), .l1clk(lsu_c2_r_clk), .* ); rvoclkhdr lsu_store_c1m_cgc (.en(lsu_store_c1_m_clken), .l1clk(lsu_store_c1_m_clk), .*); rvoclkhdr lsu_store_c1r_cgc (.en(lsu_store_c1_r_clken), .l1clk(lsu_store_c1_r_clk), .*); rvoclkhdr lsu_stbuf_c1_cgc ( .en(lsu_stbuf_c1_clken), .l1clk(lsu_stbuf_c1_clk), .* ); rvoclkhdr lsu_bus_ibuf_c1_cgc ( .en(lsu_bus_ibuf_c1_clken), .l1clk(lsu_bus_ibuf_c1_clk), .* ); rvoclkhdr lsu_bus_buf_c1_cgc ( .en(lsu_bus_buf_c1_clken), .l1clk(lsu_bus_buf_c1_clk), .* ); assign lsu_busm_clken = (~lsu_bus_buffer_empty_any | lsu_busreq_r | clk_override) & lsu_bus_clk_en; `ifdef RV_FPGA_OPTIMIZE assign lsu_busm_clk = 1'b0; assign lsu_bus_obuf_c1_clk = 1'b0; `else rvclkhdr lsu_bus_obuf_c1_cgc ( .en(lsu_bus_obuf_c1_clken), .l1clk(lsu_bus_obuf_c1_clk), .* ); rvclkhdr lsu_busm_cgc (.en(lsu_busm_clken), .l1clk(lsu_busm_clk), .*); `endif rvoclkhdr lsu_free_cgc (.en(lsu_free_c2_clken), .l1clk(lsu_free_c2_clk), .*); endmodule ================================================ FILE: design/lsu/el2_lsu_dccm_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: DCCM for LSU pipe // Comments: Single ported memory // // // DC1 -> DC2 -> DC3 -> DC4 (Commit) // // //******************************************************************************** module el2_lsu_dccm_ctl import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic lsu_c2_m_clk, // clocks input logic lsu_c2_r_clk, // clocks input logic lsu_c1_r_clk, // clocks input logic lsu_store_c1_r_clk, // clocks input logic lsu_free_c2_clk, // clocks input logic clk_override, // Override non-functional clock gating input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic rst_l, // reset, active low input el2_lsu_pkt_t lsu_pkt_r,// lsu packets input el2_lsu_pkt_t lsu_pkt_m,// lsu packets input el2_lsu_pkt_t lsu_pkt_d,// lsu packets input logic addr_in_dccm_d, // address maps to dccm input logic addr_in_pic_d, // address maps to pic input logic addr_in_pic_m, // address maps to pic input logic addr_in_dccm_m, addr_in_dccm_r, // address in dccm per pipe stage input logic addr_in_pic_r, // address in pic per pipe stage input logic lsu_raw_fwd_lo_r, lsu_raw_fwd_hi_r, input logic lsu_commit_r, // lsu instruction in r commits input logic ldst_dual_m, ldst_dual_r,// load/store is unaligned at 32 bit boundary per pipe stage // lsu address down the pipe input logic [31:0] lsu_addr_d, input logic [pt.DCCM_BITS-1:0] lsu_addr_m, input logic [31:0] lsu_addr_r, // lsu address down the pipe - needed to check unaligned input logic [pt.DCCM_BITS-1:0] end_addr_d, input logic [pt.DCCM_BITS-1:0] end_addr_m, input logic [pt.DCCM_BITS-1:0] end_addr_r, input logic stbuf_reqvld_any, // write enable input logic [pt.LSU_SB_BITS-1:0] stbuf_addr_any, // stbuf address (aligned) input logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_data_any, // the read out from stbuf input logic [pt.DCCM_ECC_WIDTH-1:0] stbuf_ecc_any, // the encoded data with ECC bits input logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_m, // stbuf fowarding to load input logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_m, // stbuf fowarding to load input logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_m, // stbuf fowarding to load input logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_m, // stbuf fowarding to load output logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_hi_r, // data from the dccm output logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_lo_r, // data from the dccm output logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_r, // data from the dccm + ecc output logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_r, output logic [pt.DCCM_DATA_WIDTH-1:0] lsu_ld_data_r, // right justified, ie load byte will have data at 7:0 output logic [pt.DCCM_DATA_WIDTH-1:0] lsu_ld_data_corr_r, // right justified & ECC corrected, ie load byte will have data at 7:0 input logic lsu_double_ecc_error_r, // lsu has a DED input logic single_ecc_error_hi_r, // sec detected on hi dccm bank input logic single_ecc_error_lo_r, // sec detected on lower dccm bank input logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_r, // corrected dccm data input logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r, // corrected dccm data input logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_r_ff, // corrected dccm data input logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r_ff, // corrected dccm data input logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_hi_r_ff, // the encoded data with ECC bits input logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_lo_r_ff, // the encoded data with ECC bits output logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_hi_m, // data from the dccm output logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_lo_m, // data from the dccm output logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_m, // data from the dccm + ecc output logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_m, output logic [pt.DCCM_DATA_WIDTH-1:0] lsu_ld_data_m, // right justified, ie load byte will have data at 7:0 input logic lsu_double_ecc_error_m, // lsu has a DED input logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_m, // corrected dccm data input logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_m, // corrected dccm data input logic [31:0] store_data_m, // Store data M-stage input logic dma_dccm_wen, // Perform DMA writes only for word/dword input logic dma_pic_wen, // Perform PIC writes input logic [2:0] dma_mem_tag_m, // DMA Buffer entry number M-stage input logic [31:0] dma_mem_addr, // DMA request address input logic [63:0] dma_mem_wdata, // DMA write data input logic [31:0] dma_dccm_wdata_lo, // Shift the dma data to lower bits to make it consistent to lsu stores input logic [31:0] dma_dccm_wdata_hi, // Shift the dma data to lower bits to make it consistent to lsu stores input logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_hi, // ECC bits for the DMA wdata input logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_lo, // ECC bits for the DMA wdata output logic [pt.DCCM_DATA_WIDTH-1:0] store_data_hi_r, output logic [pt.DCCM_DATA_WIDTH-1:0] store_data_lo_r, output logic [pt.DCCM_DATA_WIDTH-1:0] store_datafn_hi_r, // data from the dccm output logic [pt.DCCM_DATA_WIDTH-1:0] store_datafn_lo_r, // data from the dccm output logic [31:0] store_data_r, // raw store data to be sent to bus output logic ld_single_ecc_error_r, output logic ld_single_ecc_error_r_ff, output logic [31:0] picm_mask_data_m, // pic data to stbuf output logic lsu_stbuf_commit_any, // stbuf wins the dccm port or is to pic output logic lsu_dccm_rden_m, // dccm read output logic lsu_dccm_rden_r, // dccm read output logic dccm_dma_rvalid, // dccm serviving the dma load output logic dccm_dma_ecc_error, // DMA load had ecc error output logic [2:0] dccm_dma_rtag, // DMA return tag output logic [63:0] dccm_dma_rdata, // dccm data to dma request // DCCM ports output logic dccm_wren, // dccm interface -- write output logic dccm_rden, // dccm interface -- write output logic [pt.DCCM_BITS-1:0] dccm_wr_addr_lo, // dccm interface -- wr addr for lo bank output logic [pt.DCCM_BITS-1:0] dccm_wr_addr_hi, // dccm interface -- wr addr for hi bank output logic [pt.DCCM_BITS-1:0] dccm_rd_addr_lo, // dccm interface -- read address for lo bank output logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi, // dccm interface -- read address for hi bank output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo, // dccm write data for lo bank output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi, // dccm write data for hi bank input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, // dccm read data back from the dccm input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // dccm read data back from the dccm // PIC ports output logic picm_wren, // write to pic output logic picm_rden, // read to pick output logic picm_mken, // write to pic need a mask output logic [31:0] picm_rdaddr, // address for pic read access output logic [31:0] picm_wraddr, // address for pic write access output logic [31:0] picm_wr_data, // write data input logic [31:0] picm_rd_data, // read data // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // scan mode /*pragma coverage on*/ ); localparam DCCM_WIDTH_BITS = $clog2(pt.DCCM_BYTE_WIDTH); logic lsu_dccm_rden_d, lsu_dccm_wren_d; logic ld_single_ecc_error_lo_r, ld_single_ecc_error_hi_r; logic ld_single_ecc_error_lo_r_ns, ld_single_ecc_error_hi_r_ns; logic ld_single_ecc_error_lo_r_ff, ld_single_ecc_error_hi_r_ff; logic lsu_double_ecc_error_r_ff; logic [pt.DCCM_BITS-1:0] ld_sec_addr_lo_r_ff, ld_sec_addr_hi_r_ff; logic [pt.DCCM_DATA_WIDTH-1:0] store_data_lo_r_in, store_data_hi_r_in ; logic [63:0] picm_rd_data_m; logic dccm_wr_bypass_d_m_hi, dccm_wr_bypass_d_r_hi; logic dccm_wr_bypass_d_m_lo, dccm_wr_bypass_d_r_lo; logic kill_ecc_corr_lo_r, kill_ecc_corr_hi_r; // byte_en flowing down logic [3:0] store_byteen_m ,store_byteen_r; logic [7:0] store_byteen_ext_m, store_byteen_ext_r; if (pt.LOAD_TO_USE_PLUS1 == 1) begin: L2U_Plus1_1 logic [63:0] lsu_rdata_r, lsu_rdata_corr_r; logic [63:0] dccm_rdata_r, dccm_rdata_corr_r; logic [63:0] stbuf_fwddata_r; logic [7:0] stbuf_fwdbyteen_r; logic [31:0] stbuf_fwddata_lo_r, stbuf_fwddata_hi_r; logic [3:0] stbuf_fwdbyteen_lo_r, stbuf_fwdbyteen_hi_r; logic [31:0] lsu_rdata_lo_r, lsu_rdata_hi_r; logic [63:0] picm_rd_data_r; logic [63:32] lsu_ld_data_r_nc, lsu_ld_data_corr_r_nc; logic [2:0] dma_mem_tag_r; logic stbuf_fwddata_en; assign dccm_dma_rvalid = lsu_pkt_r.valid & lsu_pkt_r.load & lsu_pkt_r.dma; assign dccm_dma_ecc_error = lsu_double_ecc_error_r; assign dccm_dma_rtag[2:0] = dma_mem_tag_r[2:0]; assign dccm_dma_rdata[63:0] = ldst_dual_r ? lsu_rdata_corr_r[63:0] : {2{lsu_rdata_corr_r[31:0]}}; assign {lsu_ld_data_r_nc[63:32], lsu_ld_data_r[31:0]} = lsu_rdata_r[63:0] >> 8*lsu_addr_r[1:0]; assign {lsu_ld_data_corr_r_nc[63:32], lsu_ld_data_corr_r[31:0]} = lsu_rdata_corr_r[63:0] >> 8*lsu_addr_r[1:0]; assign picm_rd_data_r[63:32] = picm_rd_data_r[31:0]; assign dccm_rdata_r[63:0] = {dccm_rdata_hi_r[31:0],dccm_rdata_lo_r[31:0]}; assign dccm_rdata_corr_r[63:0] = {sec_data_hi_r[31:0],sec_data_lo_r[31:0]}; assign stbuf_fwddata_r[63:0] = {stbuf_fwddata_hi_r[31:0], stbuf_fwddata_lo_r[31:0]}; assign stbuf_fwdbyteen_r[7:0] = {stbuf_fwdbyteen_hi_r[3:0], stbuf_fwdbyteen_lo_r[3:0]}; assign stbuf_fwddata_en = (|stbuf_fwdbyteen_hi_m[3:0]) | (|stbuf_fwdbyteen_lo_m[3:0]) | clk_override; for (genvar i=0; i<8; i++) begin: GenDMAData assign lsu_rdata_corr_r[(8*i)+7:8*i] = stbuf_fwdbyteen_r[i] ? stbuf_fwddata_r[(8*i)+7:8*i] : (addr_in_pic_r ? picm_rd_data_r[(8*i)+7:8*i] : ({8{addr_in_dccm_r}} & dccm_rdata_corr_r[(8*i)+7:8*i])); assign lsu_rdata_r[(8*i)+7:8*i] = stbuf_fwdbyteen_r[i] ? stbuf_fwddata_r[(8*i)+7:8*i] : (addr_in_pic_r ? picm_rd_data_r[(8*i)+7:8*i] : ({8{addr_in_dccm_r}} & dccm_rdata_r[(8*i)+7:8*i])); end rvdffe #(pt.DCCM_DATA_WIDTH) dccm_rdata_hi_r_ff (.*, .din(dccm_rdata_hi_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(dccm_rdata_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .en((lsu_dccm_rden_m & ldst_dual_m) | clk_override)); rvdffe #(pt.DCCM_DATA_WIDTH) dccm_rdata_lo_r_ff (.*, .din(dccm_rdata_lo_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(dccm_rdata_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .en(lsu_dccm_rden_m | clk_override)); rvdffe #(2*pt.DCCM_ECC_WIDTH) dccm_data_ecc_r_ff (.*, .din({dccm_data_ecc_hi_m[pt.DCCM_ECC_WIDTH-1:0], dccm_data_ecc_lo_m[pt.DCCM_ECC_WIDTH-1:0]}), .dout({dccm_data_ecc_hi_r[pt.DCCM_ECC_WIDTH-1:0], dccm_data_ecc_lo_r[pt.DCCM_ECC_WIDTH-1:0]}), .en(lsu_dccm_rden_m | clk_override)); rvdff #(8) stbuf_fwdbyteen_ff (.*, .din({stbuf_fwdbyteen_hi_m[3:0], stbuf_fwdbyteen_lo_m[3:0]}), .dout({stbuf_fwdbyteen_hi_r[3:0], stbuf_fwdbyteen_lo_r[3:0]}), .clk(lsu_c2_r_clk)); rvdffe #(64) stbuf_fwddata_ff (.*, .din({stbuf_fwddata_hi_m[31:0], stbuf_fwddata_lo_m[31:0]}), .dout({stbuf_fwddata_hi_r[31:0], stbuf_fwddata_lo_r[31:0]}), .en(stbuf_fwddata_en)); rvdffe #(32) picm_rddata_rff (.*, .din(picm_rd_data_m[31:0]), .dout(picm_rd_data_r[31:0]), .en(addr_in_pic_m | clk_override)); rvdff #(3) dma_mem_tag_rff (.*, .din(dma_mem_tag_m[2:0]), .dout(dma_mem_tag_r[2:0]), .clk(lsu_c1_r_clk)); end else begin: L2U_Plus1_0 logic [63:0] lsu_rdata_m, lsu_rdata_corr_m; logic [63:0] dccm_rdata_m, dccm_rdata_corr_m; logic [63:0] stbuf_fwddata_m; logic [7:0] stbuf_fwdbyteen_m; logic [63:32] lsu_ld_data_m_nc, lsu_ld_data_corr_m_nc; logic [31:0] lsu_ld_data_corr_m; assign lsu_ld_data_r = '0; assign dccm_rdata_lo_r = '0; assign dccm_rdata_hi_r = '0; assign dccm_data_ecc_lo_r = '0; assign dccm_data_ecc_hi_r = '0; assign dccm_dma_rvalid = lsu_pkt_m.valid & lsu_pkt_m.load & lsu_pkt_m.dma; assign dccm_dma_ecc_error = lsu_double_ecc_error_m; assign dccm_dma_rtag[2:0] = dma_mem_tag_m[2:0]; assign dccm_dma_rdata[63:0] = ldst_dual_m ? lsu_rdata_corr_m[63:0] : {2{lsu_rdata_corr_m[31:0]}}; assign {lsu_ld_data_m_nc[63:32], lsu_ld_data_m[31:0]} = 64'(lsu_rdata_m[63:0] >> 8*lsu_addr_m[1:0]); assign {lsu_ld_data_corr_m_nc[63:32], lsu_ld_data_corr_m[31:0]} = 64'(lsu_rdata_corr_m[63:0] >> 8*lsu_addr_m[1:0]); assign dccm_rdata_m[63:0] = {dccm_rdata_hi_m[31:0],dccm_rdata_lo_m[31:0]}; assign dccm_rdata_corr_m[63:0] = {sec_data_hi_m[31:0],sec_data_lo_m[31:0]}; assign stbuf_fwddata_m[63:0] = {stbuf_fwddata_hi_m[31:0], stbuf_fwddata_lo_m[31:0]}; assign stbuf_fwdbyteen_m[7:0] = {stbuf_fwdbyteen_hi_m[3:0], stbuf_fwdbyteen_lo_m[3:0]}; for (genvar i=0; i<8; i++) begin: GenLoop assign lsu_rdata_corr_m[(8*i)+7:8*i] = stbuf_fwdbyteen_m[i] ? stbuf_fwddata_m[(8*i)+7:8*i] : (addr_in_pic_m ? picm_rd_data_m[(8*i)+7:8*i] : ({8{addr_in_dccm_m}} & dccm_rdata_corr_m[(8*i)+7:8*i])); assign lsu_rdata_m[(8*i)+7:8*i] = stbuf_fwdbyteen_m[i] ? stbuf_fwddata_m[(8*i)+7:8*i] : (addr_in_pic_m ? picm_rd_data_m[(8*i)+7:8*i] : ({8{addr_in_dccm_m}} & dccm_rdata_m[(8*i)+7:8*i])); end rvdffe #(32) lsu_ld_data_corr_rff(.*, .din(lsu_ld_data_corr_m[31:0]), .dout(lsu_ld_data_corr_r[31:0]), .en((lsu_pkt_m.valid & lsu_pkt_m.load & (addr_in_pic_m | addr_in_dccm_m)) | clk_override)); end assign kill_ecc_corr_lo_r = (((lsu_addr_d[pt.DCCM_BITS-1:2] == lsu_addr_r[pt.DCCM_BITS-1:2]) | (end_addr_d[pt.DCCM_BITS-1:2] == lsu_addr_r[pt.DCCM_BITS-1:2])) & lsu_pkt_d.valid & lsu_pkt_d.store & lsu_pkt_d.dma & addr_in_dccm_d) | (((lsu_addr_m[pt.DCCM_BITS-1:2] == lsu_addr_r[pt.DCCM_BITS-1:2]) | (end_addr_m[pt.DCCM_BITS-1:2] == lsu_addr_r[pt.DCCM_BITS-1:2])) & lsu_pkt_m.valid & lsu_pkt_m.store & lsu_pkt_m.dma & addr_in_dccm_m); assign kill_ecc_corr_hi_r = (((lsu_addr_d[pt.DCCM_BITS-1:2] == end_addr_r[pt.DCCM_BITS-1:2]) | (end_addr_d[pt.DCCM_BITS-1:2] == end_addr_r[pt.DCCM_BITS-1:2])) & lsu_pkt_d.valid & lsu_pkt_d.store & lsu_pkt_d.dma & addr_in_dccm_d) | (((lsu_addr_m[pt.DCCM_BITS-1:2] == end_addr_r[pt.DCCM_BITS-1:2]) | (end_addr_m[pt.DCCM_BITS-1:2] == end_addr_r[pt.DCCM_BITS-1:2])) & lsu_pkt_m.valid & lsu_pkt_m.store & lsu_pkt_m.dma & addr_in_dccm_m); assign ld_single_ecc_error_lo_r = lsu_pkt_r.load & single_ecc_error_lo_r & ~lsu_raw_fwd_lo_r; assign ld_single_ecc_error_hi_r = lsu_pkt_r.load & single_ecc_error_hi_r & ~lsu_raw_fwd_hi_r; assign ld_single_ecc_error_r = (ld_single_ecc_error_lo_r | ld_single_ecc_error_hi_r) & ~lsu_double_ecc_error_r; assign ld_single_ecc_error_lo_r_ns = ld_single_ecc_error_lo_r & (lsu_commit_r | lsu_pkt_r.dma) & ~kill_ecc_corr_lo_r; assign ld_single_ecc_error_hi_r_ns = ld_single_ecc_error_hi_r & (lsu_commit_r | lsu_pkt_r.dma) & ~kill_ecc_corr_hi_r; assign ld_single_ecc_error_r_ff = (ld_single_ecc_error_lo_r_ff | ld_single_ecc_error_hi_r_ff) & ~lsu_double_ecc_error_r_ff; assign lsu_stbuf_commit_any = stbuf_reqvld_any & (~(lsu_dccm_rden_d | lsu_dccm_wren_d | ld_single_ecc_error_r_ff) | (lsu_dccm_rden_d & ~((stbuf_addr_any[pt.DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS] == lsu_addr_d[pt.DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]) | (stbuf_addr_any[pt.DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS] == end_addr_d[pt.DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS])))); // No need to read for aligned word/dword stores since ECC will come by new data completely assign lsu_dccm_rden_d = lsu_pkt_d.valid & (lsu_pkt_d.load | (lsu_pkt_d.store & (~(lsu_pkt_d.word | lsu_pkt_d.dword) | (lsu_addr_d[1:0] != 2'b0)))) & addr_in_dccm_d; // DMA will read/write in decode stage assign lsu_dccm_wren_d = dma_dccm_wen; // DCCM inputs assign dccm_wren = lsu_dccm_wren_d | lsu_stbuf_commit_any | ld_single_ecc_error_r_ff; assign dccm_rden = lsu_dccm_rden_d & addr_in_dccm_d; assign dccm_wr_addr_lo[pt.DCCM_BITS-1:0] = ld_single_ecc_error_r_ff ? (ld_single_ecc_error_lo_r_ff ? ld_sec_addr_lo_r_ff[pt.DCCM_BITS-1:0] : ld_sec_addr_hi_r_ff[pt.DCCM_BITS-1:0]) : lsu_dccm_wren_d ? lsu_addr_d[pt.DCCM_BITS-1:0] : stbuf_addr_any[pt.DCCM_BITS-1:0]; assign dccm_wr_addr_hi[pt.DCCM_BITS-1:0] = ld_single_ecc_error_r_ff ? (ld_single_ecc_error_hi_r_ff ? ld_sec_addr_hi_r_ff[pt.DCCM_BITS-1:0] : ld_sec_addr_lo_r_ff[pt.DCCM_BITS-1:0]) : lsu_dccm_wren_d ? end_addr_d[pt.DCCM_BITS-1:0] : stbuf_addr_any[pt.DCCM_BITS-1:0]; assign dccm_rd_addr_lo[pt.DCCM_BITS-1:0] = lsu_addr_d[pt.DCCM_BITS-1:0]; assign dccm_rd_addr_hi[pt.DCCM_BITS-1:0] = end_addr_d[pt.DCCM_BITS-1:0]; assign dccm_wr_data_lo[pt.DCCM_FDATA_WIDTH-1:0] = ld_single_ecc_error_r_ff ? (ld_single_ecc_error_lo_r_ff ? {sec_data_ecc_lo_r_ff[pt.DCCM_ECC_WIDTH-1:0],sec_data_lo_r_ff[pt.DCCM_DATA_WIDTH-1:0]} : {sec_data_ecc_hi_r_ff[pt.DCCM_ECC_WIDTH-1:0],sec_data_hi_r_ff[pt.DCCM_DATA_WIDTH-1:0]}) : (dma_dccm_wen ? {dma_dccm_wdata_ecc_lo[pt.DCCM_ECC_WIDTH-1:0],dma_dccm_wdata_lo[pt.DCCM_DATA_WIDTH-1:0]} : {stbuf_ecc_any[pt.DCCM_ECC_WIDTH-1:0],stbuf_data_any[pt.DCCM_DATA_WIDTH-1:0]}); assign dccm_wr_data_hi[pt.DCCM_FDATA_WIDTH-1:0] = ld_single_ecc_error_r_ff ? (ld_single_ecc_error_hi_r_ff ? {sec_data_ecc_hi_r_ff[pt.DCCM_ECC_WIDTH-1:0],sec_data_hi_r_ff[pt.DCCM_DATA_WIDTH-1:0]} : {sec_data_ecc_lo_r_ff[pt.DCCM_ECC_WIDTH-1:0],sec_data_lo_r_ff[pt.DCCM_DATA_WIDTH-1:0]}) : (dma_dccm_wen ? {dma_dccm_wdata_ecc_hi[pt.DCCM_ECC_WIDTH-1:0],dma_dccm_wdata_hi[pt.DCCM_DATA_WIDTH-1:0]} : {stbuf_ecc_any[pt.DCCM_ECC_WIDTH-1:0],stbuf_data_any[pt.DCCM_DATA_WIDTH-1:0]}); // DCCM outputs assign store_byteen_m[3:0] = {4{lsu_pkt_m.store}} & (({4{lsu_pkt_m.by}} & 4'b0001) | ({4{lsu_pkt_m.half}} & 4'b0011) | ({4{lsu_pkt_m.word}} & 4'b1111)); assign store_byteen_r[3:0] = {4{lsu_pkt_r.store}} & (({4{lsu_pkt_r.by}} & 4'b0001) | ({4{lsu_pkt_r.half}} & 4'b0011) | ({4{lsu_pkt_r.word}} & 4'b1111)); assign store_byteen_ext_m[7:0] = {4'b0,store_byteen_m[3:0]} << lsu_addr_m[1:0]; // The packet in m assign store_byteen_ext_r[7:0] = {4'b0,store_byteen_r[3:0]} << lsu_addr_r[1:0]; assign dccm_wr_bypass_d_m_lo = (stbuf_addr_any[pt.DCCM_BITS-1:2] == lsu_addr_m[pt.DCCM_BITS-1:2]) & addr_in_dccm_m; assign dccm_wr_bypass_d_m_hi = (stbuf_addr_any[pt.DCCM_BITS-1:2] == end_addr_m[pt.DCCM_BITS-1:2]) & addr_in_dccm_m; assign dccm_wr_bypass_d_r_lo = (stbuf_addr_any[pt.DCCM_BITS-1:2] == lsu_addr_r[pt.DCCM_BITS-1:2]) & addr_in_dccm_r; assign dccm_wr_bypass_d_r_hi = (stbuf_addr_any[pt.DCCM_BITS-1:2] == end_addr_r[pt.DCCM_BITS-1:2]) & addr_in_dccm_r; if (pt.LOAD_TO_USE_PLUS1 == 1) begin: L2U1_Plus1_1 logic dccm_wren_Q; logic [31:0] dccm_wr_data_Q; logic dccm_wr_bypass_d_m_lo_Q, dccm_wr_bypass_d_m_hi_Q; logic [31:0] store_data_pre_hi_r, store_data_pre_lo_r; assign {store_data_pre_hi_r[31:0], store_data_pre_lo_r[31:0]} = {32'b0,store_data_r[31:0]} << 8*lsu_addr_r[1:0]; for (genvar i=0; i<4; i++) begin assign store_data_lo_r[(8*i)+7:(8*i)] = store_byteen_ext_r[i] ? store_data_pre_lo_r[(8*i)+7:(8*i)] : ((dccm_wren_Q & dccm_wr_bypass_d_m_lo_Q) ? dccm_wr_data_Q[(8*i)+7:(8*i)] : sec_data_lo_r[(8*i)+7:(8*i)]); assign store_data_hi_r[(8*i)+7:(8*i)] = store_byteen_ext_r[i+4] ? store_data_pre_hi_r[(8*i)+7:(8*i)] : ((dccm_wren_Q & dccm_wr_bypass_d_m_hi_Q) ? dccm_wr_data_Q[(8*i)+7:(8*i)] : sec_data_hi_r[(8*i)+7:(8*i)]); assign store_datafn_lo_r[(8*i)+7:(8*i)] = store_byteen_ext_r[i] ? store_data_pre_lo_r[(8*i)+7:(8*i)] : ((lsu_stbuf_commit_any & dccm_wr_bypass_d_r_lo) ? stbuf_data_any[(8*i)+7:(8*i)] : ((dccm_wren_Q & dccm_wr_bypass_d_m_lo_Q) ? dccm_wr_data_Q[(8*i)+7:(8*i)] : sec_data_lo_r[(8*i)+7:(8*i)])); assign store_datafn_hi_r[(8*i)+7:(8*i)] = store_byteen_ext_r[i+4] ? store_data_pre_hi_r[(8*i)+7:(8*i)] : ((lsu_stbuf_commit_any & dccm_wr_bypass_d_r_hi) ? stbuf_data_any[(8*i)+7:(8*i)] : ((dccm_wren_Q & dccm_wr_bypass_d_m_hi_Q) ? dccm_wr_data_Q[(8*i)+7:(8*i)] : sec_data_hi_r[(8*i)+7:(8*i)])); end rvdff #(1) dccm_wren_ff (.*, .din(lsu_stbuf_commit_any), .dout(dccm_wren_Q), .clk(lsu_free_c2_clk)); // ECC load errors writing to dccm shouldn't fwd to stores in pipe rvdffe #(32) dccm_wrdata_ff (.*, .din(stbuf_data_any[31:0]), .dout(dccm_wr_data_Q[31:0]), .en(lsu_stbuf_commit_any | clk_override), .clk(clk)); rvdff #(1) dccm_wrbyp_dm_loff (.*, .din(dccm_wr_bypass_d_m_lo), .dout(dccm_wr_bypass_d_m_lo_Q), .clk(lsu_free_c2_clk)); rvdff #(1) dccm_wrbyp_dm_hiff (.*, .din(dccm_wr_bypass_d_m_hi), .dout(dccm_wr_bypass_d_m_hi_Q), .clk(lsu_free_c2_clk)); rvdff #(32) store_data_rff (.*, .din(store_data_m[31:0]), .dout(store_data_r[31:0]), .clk(lsu_store_c1_r_clk)); end else begin: L2U1_Plus1_0 logic [31:0] store_data_hi_m, store_data_lo_m; logic [63:0] store_data_mask; assign {store_data_hi_m[31:0] , store_data_lo_m[31:0]} = {32'b0,store_data_m[31:0]} << 8*lsu_addr_m[1:0]; for (genvar i=0; i<4; i++) begin assign store_data_hi_r_in[(8*i)+7:(8*i)] = store_byteen_ext_m[i+4] ? store_data_hi_m[(8*i)+7:(8*i)] : ((lsu_stbuf_commit_any & dccm_wr_bypass_d_m_hi) ? stbuf_data_any[(8*i)+7:(8*i)] : sec_data_hi_m[(8*i)+7:(8*i)]); assign store_data_lo_r_in[(8*i)+7:(8*i)] = store_byteen_ext_m[i] ? store_data_lo_m[(8*i)+7:(8*i)] : ((lsu_stbuf_commit_any & dccm_wr_bypass_d_m_lo) ? stbuf_data_any[(8*i)+7:(8*i)] : sec_data_lo_m[(8*i)+7:(8*i)]); assign store_datafn_lo_r[(8*i)+7:(8*i)] = (lsu_stbuf_commit_any & dccm_wr_bypass_d_r_lo & ~store_byteen_ext_r[i]) ? stbuf_data_any[(8*i)+7:(8*i)] : store_data_lo_r[(8*i)+7:(8*i)]; assign store_datafn_hi_r[(8*i)+7:(8*i)] = (lsu_stbuf_commit_any & dccm_wr_bypass_d_r_hi & ~store_byteen_ext_r[i+4]) ? stbuf_data_any[(8*i)+7:(8*i)] : store_data_hi_r[(8*i)+7:(8*i)]; end // for (genvar i=0; i> 8*lsu_addr_r[1:0]) & store_data_mask[31:0]; rvdffe #(pt.DCCM_DATA_WIDTH) store_data_hi_rff (.*, .din(store_data_hi_r_in[pt.DCCM_DATA_WIDTH-1:0]), .dout(store_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .en((ldst_dual_m & lsu_pkt_m.valid & lsu_pkt_m.store) | clk_override), .clk(clk)); rvdff #(pt.DCCM_DATA_WIDTH) store_data_lo_rff (.*, .din(store_data_lo_r_in[pt.DCCM_DATA_WIDTH-1:0]), .dout(store_data_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .clk(lsu_store_c1_r_clk)); end assign dccm_rdata_lo_m[pt.DCCM_DATA_WIDTH-1:0] = dccm_rd_data_lo[pt.DCCM_DATA_WIDTH-1:0]; // for ld choose dccm_out assign dccm_rdata_hi_m[pt.DCCM_DATA_WIDTH-1:0] = dccm_rd_data_hi[pt.DCCM_DATA_WIDTH-1:0]; // for ld this is used for ecc assign dccm_data_ecc_lo_m[pt.DCCM_ECC_WIDTH-1:0] = dccm_rd_data_lo[pt.DCCM_FDATA_WIDTH-1:pt.DCCM_DATA_WIDTH]; assign dccm_data_ecc_hi_m[pt.DCCM_ECC_WIDTH-1:0] = dccm_rd_data_hi[pt.DCCM_FDATA_WIDTH-1:pt.DCCM_DATA_WIDTH]; // PIC signals. PIC ignores the lower 2 bits of address since PIC memory registers are 32-bits assign picm_wren = (lsu_pkt_r.valid & lsu_pkt_r.store & addr_in_pic_r & lsu_commit_r) | dma_pic_wen; assign picm_rden = lsu_pkt_d.valid & lsu_pkt_d.load & addr_in_pic_d; assign picm_mken = lsu_pkt_d.valid & lsu_pkt_d.store & addr_in_pic_d; // Get the mask for stores assign picm_rdaddr[31:0] = pt.PIC_BASE_ADDR | {{32-pt.PIC_BITS{1'b0}},lsu_addr_d[pt.PIC_BITS-1:0]}; assign picm_wraddr[31:0] = pt.PIC_BASE_ADDR | {{32-pt.PIC_BITS{1'b0}},(dma_pic_wen ? dma_mem_addr[pt.PIC_BITS-1:0] : lsu_addr_r[pt.PIC_BITS-1:0])}; assign picm_wr_data[31:0] = dma_pic_wen ? dma_mem_wdata[31:0] : store_datafn_lo_r[31:0]; assign picm_mask_data_m[31:0] = picm_rd_data_m[31:0]; assign picm_rd_data_m[63:0] = {picm_rd_data[31:0],picm_rd_data[31:0]}; if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable rvdff #(1) dccm_rden_mff (.*, .din(lsu_dccm_rden_d), .dout(lsu_dccm_rden_m), .clk(lsu_c2_m_clk)); rvdff #(1) dccm_rden_rff (.*, .din(lsu_dccm_rden_m), .dout(lsu_dccm_rden_r), .clk(lsu_c2_r_clk)); // ECC correction flops since dccm write happens next cycle // We are writing to dccm in r+1 for ecc correction since fast_int needs to be blocked in decode - 1. We can probably write in r for plus0 configuration since we know ecc error in M. // In that case these (_ff) flops are needed only in plus1 configuration rvdff #(1) ld_double_ecc_error_rff (.*, .din(lsu_double_ecc_error_r), .dout(lsu_double_ecc_error_r_ff), .clk(lsu_free_c2_clk)); rvdff #(1) ld_single_ecc_error_hi_rff (.*, .din(ld_single_ecc_error_hi_r_ns), .dout(ld_single_ecc_error_hi_r_ff), .clk(lsu_free_c2_clk)); rvdff #(1) ld_single_ecc_error_lo_rff (.*, .din(ld_single_ecc_error_lo_r_ns), .dout(ld_single_ecc_error_lo_r_ff), .clk(lsu_free_c2_clk)); rvdffe #(pt.DCCM_BITS) ld_sec_addr_hi_rff (.*, .din(end_addr_r[pt.DCCM_BITS-1:0]), .dout(ld_sec_addr_hi_r_ff[pt.DCCM_BITS-1:0]), .en(ld_single_ecc_error_r | clk_override), .clk(clk)); rvdffe #(pt.DCCM_BITS) ld_sec_addr_lo_rff (.*, .din(lsu_addr_r[pt.DCCM_BITS-1:0]), .dout(ld_sec_addr_lo_r_ff[pt.DCCM_BITS-1:0]), .en(ld_single_ecc_error_r | clk_override), .clk(clk)); end else begin: Gen_dccm_disable assign lsu_dccm_rden_m = '0; assign lsu_dccm_rden_r = '0; assign lsu_double_ecc_error_r_ff = 1'b0; assign ld_single_ecc_error_hi_r_ff = 1'b0; assign ld_single_ecc_error_lo_r_ff = 1'b0; assign ld_sec_addr_hi_r_ff[pt.DCCM_BITS-1:0] = '0; assign ld_sec_addr_lo_r_ff[pt.DCCM_BITS-1:0] = '0; end `ifdef RV_ASSERT_ON // Load single ECC error correction implies commit/dma property ld_single_ecc_error_commit; @(posedge clk) disable iff(~rst_l) (ld_single_ecc_error_r_ff & dccm_wren) |-> ($past(lsu_commit_r | lsu_pkt_r.dma)); endproperty assert_ld_single_ecc_error_commit: assert property (ld_single_ecc_error_commit) else $display("No commit or DMA but ECC correction happened"); `endif endmodule ================================================ FILE: design/lsu/el2_lsu_dccm_mem.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // Copyright (c) 2023 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: DCCM for LSU pipe // Comments: Single ported memory // // // DC1 -> DC2 -> DC3 -> DC4 (Commit) // // //******************************************************************************** module el2_lsu_dccm_mem import el2_pkg::*; #( `include "el2_param.vh" )( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic rst_l, // reset, active low input logic clk_override, // Override non-functional clock gating input logic dccm_wren, // write enable input logic dccm_rden, // read enable input logic [pt.DCCM_BITS-1:0] dccm_wr_addr_lo, // write address input logic [pt.DCCM_BITS-1:0] dccm_wr_addr_hi, // write address input logic [pt.DCCM_BITS-1:0] dccm_rd_addr_lo, // read address input logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi, // read address for the upper bank in case of a misaligned access input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo, // write data input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi, // write data el2_mem_if.veer_dccm dccm_mem_export, // RAM repositioned in testbench and connected by this interface output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, // read data from the lo bank output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, // read data from the hi bank // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode /*pragma coverage on*/ ); localparam logic [5:0] DCCM_WIDTH_BITS = $clog2(pt.DCCM_BYTE_WIDTH); localparam logic [7:0] DCCM_INDEX_BITS = 8'(pt.DCCM_BITS - pt.DCCM_BANK_BITS - pt.DCCM_WIDTH_BITS); localparam logic [31:0] DCCM_INDEX_DEPTH = ((pt.DCCM_SIZE)*1024)/((pt.DCCM_BYTE_WIDTH)*(pt.DCCM_NUM_BANKS)); // Depth of memory bank logic [pt.DCCM_NUM_BANKS-1:0] wren_bank; logic [pt.DCCM_NUM_BANKS-1:0] rden_bank; logic [pt.DCCM_NUM_BANKS-1:0] [pt.DCCM_BITS-1:(pt.DCCM_BANK_BITS+2)] addr_bank; logic rd_unaligned, wr_unaligned; logic [pt.DCCM_NUM_BANKS-1:0] [pt.DCCM_FDATA_WIDTH-1:0] dccm_bank_dout; logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_FDATA_WIDTH-1:0] wr_data_bank; logic [(DCCM_WIDTH_BITS+pt.DCCM_BANK_BITS-1):DCCM_WIDTH_BITS] dccm_rd_addr_lo_q; logic [(DCCM_WIDTH_BITS+pt.DCCM_BANK_BITS-1):DCCM_WIDTH_BITS] dccm_rd_addr_hi_q; logic [pt.DCCM_NUM_BANKS-1:0] dccm_clken; assign rd_unaligned = (dccm_rd_addr_lo[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS] != dccm_rd_addr_hi[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]); assign wr_unaligned = (dccm_wr_addr_lo[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS] != dccm_wr_addr_hi[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]); // Align the read data assign dccm_rd_data_lo[pt.DCCM_FDATA_WIDTH-1:0] = dccm_bank_dout[dccm_rd_addr_lo_q[pt.DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]][pt.DCCM_FDATA_WIDTH-1:0]; assign dccm_rd_data_hi[pt.DCCM_FDATA_WIDTH-1:0] = dccm_bank_dout[dccm_rd_addr_hi_q[DCCM_WIDTH_BITS+:pt.DCCM_BANK_BITS]][pt.DCCM_FDATA_WIDTH-1:0]; // 8 Banks, 16KB each (2048 x 72) for (genvar i=0; i DC2 -> DC3 -> DC4 (Commit) // //******************************************************************************** module el2_lsu_ecc import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic lsu_c2_r_clk, // clock input logic clk_override, // Override non-functional clock gating input logic rst_l, // reset, active low // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, // scan mode /*pragma coverage on*/ input el2_lsu_pkt_t lsu_pkt_m, // packet in m input el2_lsu_pkt_t lsu_pkt_r, // packet in r input logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_data_any, input logic dec_tlu_core_ecc_disable, // disables the ecc computation and error flagging input logic lsu_dccm_rden_r, // dccm rden input logic addr_in_dccm_r, // address in dccm input logic [pt.DCCM_BITS-1:0] lsu_addr_r, // start address input logic [pt.DCCM_BITS-1:0] end_addr_r, // end address input logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_hi_r, // data from the dccm input logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_lo_r, // data from the dccm input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_r, // data from the dccm + ecc input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_r, // data from the dccm + ecc output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_r, // corrected dccm data R-stage output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r, // corrected dccm data R-stage output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_r_ff, // corrected dccm data R+1 stage output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_r_ff, // corrected dccm data R+1 stage input logic ld_single_ecc_error_r, // ld has a single ecc error input logic ld_single_ecc_error_r_ff, // ld has a single ecc error input logic lsu_dccm_rden_m, // dccm rden input logic addr_in_dccm_m, // address in dccm input logic [pt.DCCM_BITS-1:0] lsu_addr_m, // start address input logic [pt.DCCM_BITS-1:0] end_addr_m, // end address input logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_hi_m, // raw data from mem input logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_lo_m, // raw data from mem input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_m, // ecc read out from mem input logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_lo_m, // ecc read out from mem output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_m, // corrected dccm data M-stage output logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_lo_m, // corrected dccm data M-stage input logic dma_dccm_wen, // Perform DMA writes only for word/dword input logic [31:0] dma_dccm_wdata_lo, // Shifted dma data to lower bits to make it consistent to lsu stores input logic [31:0] dma_dccm_wdata_hi, // Shifted dma data to lower bits to make it consistent to lsu stores output logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_hi, // ECC bits for the DMA wdata output logic [pt.DCCM_ECC_WIDTH-1:0] dma_dccm_wdata_ecc_lo, // ECC bits for the DMA wdata output logic [pt.DCCM_ECC_WIDTH-1:0] stbuf_ecc_any, // Encoded data with ECC bits output logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_hi_r_ff, // Encoded data with ECC bits output logic [pt.DCCM_ECC_WIDTH-1:0] sec_data_ecc_lo_r_ff, // Encoded data with ECC bits output logic single_ecc_error_hi_r, // sec detected output logic single_ecc_error_lo_r, // sec detected on lower dccm bank output logic lsu_single_ecc_error_r, // or of the 2 output logic lsu_double_ecc_error_r, // double error detected output logic lsu_single_ecc_error_m, // or of the 2 output logic lsu_double_ecc_error_m // double error detected ); logic is_ldst_r; logic is_ldst_hi_any, is_ldst_lo_any; logic [pt.DCCM_DATA_WIDTH-1:0] dccm_wdata_hi_any, dccm_wdata_lo_any; logic [pt.DCCM_ECC_WIDTH-1:0] dccm_wdata_ecc_hi_any, dccm_wdata_ecc_lo_any; logic [pt.DCCM_DATA_WIDTH-1:0] dccm_rdata_hi_any, dccm_rdata_lo_any; logic [pt.DCCM_ECC_WIDTH-1:0] dccm_data_ecc_hi_any, dccm_data_ecc_lo_any; logic [pt.DCCM_DATA_WIDTH-1:0] sec_data_hi_any, sec_data_lo_any; logic single_ecc_error_hi_any, single_ecc_error_lo_any; logic double_ecc_error_hi_any, double_ecc_error_lo_any; logic double_ecc_error_hi_m, double_ecc_error_lo_m; logic double_ecc_error_hi_r, double_ecc_error_lo_r; logic [6:0] ecc_out_hi_nc, ecc_out_lo_nc; if (pt.LOAD_TO_USE_PLUS1 == 1) begin: L2U_Plus1_1 logic ldst_dual_m, ldst_dual_r; logic is_ldst_m; logic is_ldst_hi_r, is_ldst_lo_r; assign ldst_dual_r = (lsu_addr_r[2] != end_addr_r[2]); assign is_ldst_r = lsu_pkt_r.valid & (lsu_pkt_r.load | lsu_pkt_r.store) & addr_in_dccm_r & lsu_dccm_rden_r; assign is_ldst_lo_r = is_ldst_r & ~dec_tlu_core_ecc_disable; assign is_ldst_hi_r = is_ldst_r & ldst_dual_r & ~dec_tlu_core_ecc_disable; // Always check the ECC Hi/Lo for DMA since we don't align for DMA assign is_ldst_hi_any = is_ldst_hi_r; assign dccm_rdata_hi_any[pt.DCCM_DATA_WIDTH-1:0] = dccm_rdata_hi_r[pt.DCCM_DATA_WIDTH-1:0]; assign dccm_data_ecc_hi_any[pt.DCCM_ECC_WIDTH-1:0] = dccm_data_ecc_hi_r[pt.DCCM_ECC_WIDTH-1:0]; assign is_ldst_lo_any = is_ldst_lo_r; assign dccm_rdata_lo_any[pt.DCCM_DATA_WIDTH-1:0] = dccm_rdata_lo_r[pt.DCCM_DATA_WIDTH-1:0]; assign dccm_data_ecc_lo_any[pt.DCCM_ECC_WIDTH-1:0] = dccm_data_ecc_lo_r[pt.DCCM_ECC_WIDTH-1:0]; assign sec_data_hi_r[pt.DCCM_DATA_WIDTH-1:0] = sec_data_hi_any[pt.DCCM_DATA_WIDTH-1:0]; assign single_ecc_error_hi_r = single_ecc_error_hi_any; assign double_ecc_error_hi_r = double_ecc_error_hi_any; assign sec_data_lo_r[pt.DCCM_DATA_WIDTH-1:0] = sec_data_lo_any[pt.DCCM_DATA_WIDTH-1:0]; assign single_ecc_error_lo_r = single_ecc_error_lo_any; assign double_ecc_error_lo_r = double_ecc_error_lo_any; assign lsu_single_ecc_error_r = single_ecc_error_hi_r | single_ecc_error_lo_r; assign lsu_double_ecc_error_r = double_ecc_error_hi_r | double_ecc_error_lo_r; end else begin: L2U_Plus1_0 logic ldst_dual_m; logic is_ldst_m; logic is_ldst_hi_m, is_ldst_lo_m; assign ldst_dual_m = (lsu_addr_m[2] != end_addr_m[2]); assign is_ldst_m = lsu_pkt_m.valid & (lsu_pkt_m.load | lsu_pkt_m.store) & addr_in_dccm_m & lsu_dccm_rden_m; assign is_ldst_lo_m = is_ldst_m & ~dec_tlu_core_ecc_disable; assign is_ldst_hi_m = is_ldst_m & (ldst_dual_m | lsu_pkt_m.dma) & ~dec_tlu_core_ecc_disable; // Always check the ECC Hi/Lo for DMA since we don't align for DMA assign is_ldst_hi_any = is_ldst_hi_m; assign dccm_rdata_hi_any[pt.DCCM_DATA_WIDTH-1:0] = dccm_rdata_hi_m[pt.DCCM_DATA_WIDTH-1:0]; assign dccm_data_ecc_hi_any[pt.DCCM_ECC_WIDTH-1:0] = dccm_data_ecc_hi_m[pt.DCCM_ECC_WIDTH-1:0]; assign is_ldst_lo_any = is_ldst_lo_m; assign dccm_rdata_lo_any[pt.DCCM_DATA_WIDTH-1:0] = dccm_rdata_lo_m[pt.DCCM_DATA_WIDTH-1:0]; assign dccm_data_ecc_lo_any[pt.DCCM_ECC_WIDTH-1:0] = dccm_data_ecc_lo_m[pt.DCCM_ECC_WIDTH-1:0]; assign sec_data_hi_m[pt.DCCM_DATA_WIDTH-1:0] = sec_data_hi_any[pt.DCCM_DATA_WIDTH-1:0]; assign double_ecc_error_hi_m = double_ecc_error_hi_any; assign sec_data_lo_m[pt.DCCM_DATA_WIDTH-1:0] = sec_data_lo_any[pt.DCCM_DATA_WIDTH-1:0]; assign double_ecc_error_lo_m = double_ecc_error_lo_any; assign lsu_single_ecc_error_m = single_ecc_error_hi_any | single_ecc_error_lo_any; assign lsu_double_ecc_error_m = double_ecc_error_hi_m | double_ecc_error_lo_m; // Flops rvdff #(1) lsu_single_ecc_err_r (.din(lsu_single_ecc_error_m), .dout(lsu_single_ecc_error_r), .clk(lsu_c2_r_clk), .*); rvdff #(1) lsu_double_ecc_err_r (.din(lsu_double_ecc_error_m), .dout(lsu_double_ecc_error_r), .clk(lsu_c2_r_clk), .*); rvdff #(.WIDTH(1)) ldst_sec_lo_rff (.din(single_ecc_error_lo_any), .dout(single_ecc_error_lo_r), .clk(lsu_c2_r_clk), .*); rvdff #(.WIDTH(1)) ldst_sec_hi_rff (.din(single_ecc_error_hi_any), .dout(single_ecc_error_hi_r), .clk(lsu_c2_r_clk), .*); rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_hi_rff (.din(sec_data_hi_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .en(lsu_single_ecc_error_m | clk_override), .*); rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_lo_rff (.din(sec_data_lo_m[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .en(lsu_single_ecc_error_m | clk_override), .*); end // Logic for ECC generation during write assign dccm_wdata_lo_any[pt.DCCM_DATA_WIDTH-1:0] = ld_single_ecc_error_r_ff ? sec_data_lo_r_ff[pt.DCCM_DATA_WIDTH-1:0] : (dma_dccm_wen ? dma_dccm_wdata_lo[pt.DCCM_DATA_WIDTH-1:0] : stbuf_data_any[pt.DCCM_DATA_WIDTH-1:0]); assign dccm_wdata_hi_any[pt.DCCM_DATA_WIDTH-1:0] = ld_single_ecc_error_r_ff ? sec_data_hi_r_ff[pt.DCCM_DATA_WIDTH-1:0] : (dma_dccm_wen ? dma_dccm_wdata_hi[pt.DCCM_DATA_WIDTH-1:0] : 32'h0); assign sec_data_ecc_hi_r_ff[pt.DCCM_ECC_WIDTH-1:0] = dccm_wdata_ecc_hi_any[pt.DCCM_ECC_WIDTH-1:0]; assign sec_data_ecc_lo_r_ff[pt.DCCM_ECC_WIDTH-1:0] = dccm_wdata_ecc_lo_any[pt.DCCM_ECC_WIDTH-1:0]; assign stbuf_ecc_any[pt.DCCM_ECC_WIDTH-1:0] = dccm_wdata_ecc_lo_any[pt.DCCM_ECC_WIDTH-1:0]; assign dma_dccm_wdata_ecc_hi[pt.DCCM_ECC_WIDTH-1:0] = dccm_wdata_ecc_hi_any[pt.DCCM_ECC_WIDTH-1:0]; assign dma_dccm_wdata_ecc_lo[pt.DCCM_ECC_WIDTH-1:0] = dccm_wdata_ecc_lo_any[pt.DCCM_ECC_WIDTH-1:0]; // Instantiate ECC blocks if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable //Detect/Repair for Hi rvecc_decode lsu_ecc_decode_hi ( // Inputs .en(is_ldst_hi_any), .sed_ded (1'b0), // 1 : means only detection .din(dccm_rdata_hi_any[pt.DCCM_DATA_WIDTH-1:0]), .ecc_in(dccm_data_ecc_hi_any[pt.DCCM_ECC_WIDTH-1:0]), // Outputs .dout(sec_data_hi_any[pt.DCCM_DATA_WIDTH-1:0]), .ecc_out (ecc_out_hi_nc[6:0]), .single_ecc_error(single_ecc_error_hi_any), .double_ecc_error(double_ecc_error_hi_any), .* ); //Detect/Repair for Lo rvecc_decode lsu_ecc_decode_lo ( // Inputs .en(is_ldst_lo_any), .sed_ded (1'b0), // 1 : means only detection .din(dccm_rdata_lo_any[pt.DCCM_DATA_WIDTH-1:0] ), .ecc_in(dccm_data_ecc_lo_any[pt.DCCM_ECC_WIDTH-1:0]), // Outputs .dout(sec_data_lo_any[pt.DCCM_DATA_WIDTH-1:0]), .ecc_out (ecc_out_lo_nc[6:0]), .single_ecc_error(single_ecc_error_lo_any), .double_ecc_error(double_ecc_error_lo_any), .* ); rvecc_encode lsu_ecc_encode_hi ( //Inputs .din(dccm_wdata_hi_any[pt.DCCM_DATA_WIDTH-1:0]), //Outputs .ecc_out(dccm_wdata_ecc_hi_any[pt.DCCM_ECC_WIDTH-1:0]), .* ); rvecc_encode lsu_ecc_encode_lo ( //Inputs .din(dccm_wdata_lo_any[pt.DCCM_DATA_WIDTH-1:0]), //Outputs .ecc_out(dccm_wdata_ecc_lo_any[pt.DCCM_ECC_WIDTH-1:0]), .* ); end else begin: Gen_dccm_disable // block: Gen_dccm_enable assign sec_data_hi_any[pt.DCCM_DATA_WIDTH-1:0] = '0; assign sec_data_lo_any[pt.DCCM_DATA_WIDTH-1:0] = '0; assign single_ecc_error_hi_any = '0; assign double_ecc_error_hi_any = '0; assign single_ecc_error_lo_any = '0; assign double_ecc_error_lo_any = '0; end rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_hi_rplus1ff (.din(sec_data_hi_r[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_hi_r_ff[pt.DCCM_DATA_WIDTH-1:0]), .en(ld_single_ecc_error_r | clk_override), .clk(clk), .*); rvdffe #(.WIDTH(pt.DCCM_DATA_WIDTH)) sec_data_lo_rplus1ff (.din(sec_data_lo_r[pt.DCCM_DATA_WIDTH-1:0]), .dout(sec_data_lo_r_ff[pt.DCCM_DATA_WIDTH-1:0]), .en(ld_single_ecc_error_r | clk_override), .clk(clk), .*); endmodule // el2_lsu_ecc ================================================ FILE: design/lsu/el2_lsu_lsc_ctl.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: LSU control // Comments: // // // DC1 -> DC2 -> DC3 -> DC4 (Commit) // //******************************************************************************** module el2_lsu_lsc_ctl import el2_pkg::*; #( `include "el2_param.vh" )( input logic rst_l, // reset, active low input logic clk_override, // Override non-functional clock gating input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. // clocks per pipe input logic lsu_c1_m_clk, input logic lsu_c1_r_clk, input logic lsu_c2_m_clk, input logic lsu_c2_r_clk, input logic lsu_store_c1_m_clk, input logic [31:0] lsu_ld_data_r, // Load data R-stage input logic [31:0] lsu_ld_data_corr_r, // ECC corrected data R-stage input logic lsu_single_ecc_error_r, // ECC single bit error R-stage input logic lsu_double_ecc_error_r, // ECC double bit error R-stage input logic [31:0] lsu_ld_data_m, // Load data M-stage input logic lsu_single_ecc_error_m, // ECC single bit error M-stage input logic lsu_double_ecc_error_m, // ECC double bit error M-stage input logic flush_m_up, // Flush M and D stage input logic flush_r, // Flush R-stage input logic ldst_dual_d, // load/store is unaligned at 32 bit boundary D-stage input logic ldst_dual_m, // load/store is unaligned at 32 bit boundary M-stage input logic ldst_dual_r, // load/store is unaligned at 32 bit boundary R-stage input logic [31:0] exu_lsu_rs1_d, // address input logic [31:0] exu_lsu_rs2_d, // store data input el2_lsu_pkt_t lsu_p, // lsu control packet input logic dec_lsu_valid_raw_d, // Raw valid for address computation input logic [11:0] dec_lsu_offset_d, // 12b offset for load/store addresses input logic [31:0] picm_mask_data_m, // PIC data M-stage input logic [31:0] bus_read_data_m, // the bus return data output logic [31:0] lsu_result_m, // lsu load data output logic [31:0] lsu_result_corr_r, // This is the ECC corrected data going to RF // lsu address down the pipe output logic [31:0] lsu_addr_d, output logic [31:0] lsu_addr_m, output logic [31:0] lsu_addr_r, // lsu address down the pipe - needed to check unaligned output logic [31:0] end_addr_d, output logic [31:0] end_addr_m, output logic [31:0] end_addr_r, // store data down the pipe output logic [31:0] store_data_m, input logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control output logic lsu_exc_m, // Access or misaligned fault output logic is_sideeffects_m, // is sideffects space output logic lsu_commit_r, // lsu instruction in r commits output logic lsu_single_ecc_error_incr,// LSU inc SB error counter output el2_lsu_error_pkt_t lsu_error_pkt_r, // lsu exception packet output logic [31:1] lsu_fir_addr, // fast interrupt address output logic [1:0] lsu_fir_error, // Error during fast interrupt lookup // address in dccm/pic/external per pipe stage output logic addr_in_dccm_d, output logic addr_in_dccm_m, output logic addr_in_dccm_r, output logic addr_in_pic_d, output logic addr_in_pic_m, output logic addr_in_pic_r, output logic addr_external_m, // DMA slave input logic dma_dccm_req, input logic [31:0] dma_mem_addr, input logic [2:0] dma_mem_sz, input logic dma_mem_write, input logic [63:0] dma_mem_wdata, // Store buffer related signals output el2_lsu_pkt_t lsu_pkt_d, output el2_lsu_pkt_t lsu_pkt_m, output el2_lsu_pkt_t lsu_pkt_r, input logic lsu_pmp_error_start, input logic lsu_pmp_error_end, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // Scan mode /*pragma coverage on*/ ); logic [31:3] end_addr_pre_m, end_addr_pre_r; logic [31:0] full_addr_d; logic [31:0] full_end_addr_d; logic [31:0] lsu_rs1_d; logic [11:0] lsu_offset_d; logic [31:0] rs1_d; logic [11:0] offset_d; logic [12:0] end_addr_offset_d; logic [2:0] addr_offset_d; logic [63:0] dma_mem_wdata_shifted; logic addr_external_d; logic addr_external_r; logic access_fault_d, misaligned_fault_d; logic access_fault_m, misaligned_fault_m; logic fir_dccm_access_error_d, fir_nondccm_access_error_d; logic fir_dccm_access_error_m, fir_nondccm_access_error_m; logic [3:0] exc_mscause_d, exc_mscause_m; logic [31:0] rs1_d_raw; logic [31:0] store_data_d, store_data_pre_m, store_data_m_in; logic [31:0] bus_read_data_r; el2_lsu_pkt_t dma_pkt_d; el2_lsu_pkt_t lsu_pkt_m_in, lsu_pkt_r_in; el2_lsu_error_pkt_t lsu_error_pkt_m; // Premux the rs1/offset for dma assign lsu_rs1_d[31:0] = dec_lsu_valid_raw_d ? exu_lsu_rs1_d[31:0] : dma_mem_addr[31:0]; assign lsu_offset_d[11:0] = dec_lsu_offset_d[11:0] & {12{dec_lsu_valid_raw_d}}; assign rs1_d_raw[31:0] = lsu_rs1_d[31:0]; assign offset_d[11:0] = lsu_offset_d[11:0]; assign rs1_d[31:0] = (lsu_pkt_d.load_ldst_bypass_d) ? lsu_result_m[31:0] : rs1_d_raw[31:0]; // generate the ls address rvlsadder lsadder (.rs1(rs1_d[31:0]), .offset(offset_d[11:0]), .dout(full_addr_d[31:0]) ); // Module to generate the memory map of the address el2_lsu_addrcheck addrcheck ( .start_addr_d(full_addr_d[31:0]), .end_addr_d(full_end_addr_d[31:0]), .rs1_region_d(rs1_d[31:28]), .* ); // Calculate start/end address for load/store assign addr_offset_d[2:0] = ({3{lsu_pkt_d.half}} & 3'b01) | ({3{lsu_pkt_d.word}} & 3'b11) | ({3{lsu_pkt_d.dword}} & 3'b111); assign end_addr_offset_d[12:0] = {offset_d[11],offset_d[11:0]} + {9'b0,addr_offset_d[2:0]}; assign full_end_addr_d[31:0] = rs1_d[31:0] + {{19{end_addr_offset_d[12]}},end_addr_offset_d[12:0]}; assign end_addr_d[31:0] = full_end_addr_d[31:0]; assign lsu_exc_m = access_fault_m | misaligned_fault_m; // Goes to TLU to increment the ECC error counter assign lsu_single_ecc_error_incr = (lsu_single_ecc_error_r & ~lsu_double_ecc_error_r) & (lsu_commit_r | lsu_pkt_r.dma) & lsu_pkt_r.valid; if (pt.LOAD_TO_USE_PLUS1 == 1) begin: L2U_Plus1_1 logic access_fault_r, misaligned_fault_r; logic [3:0] exc_mscause_r; logic fir_dccm_access_error_r, fir_nondccm_access_error_r; // Generate exception packet assign lsu_error_pkt_r.exc_valid = (access_fault_r | misaligned_fault_r | lsu_double_ecc_error_r) & lsu_pkt_r.valid & ~lsu_pkt_r.dma & ~lsu_pkt_r.fast_int; assign lsu_error_pkt_r.single_ecc_error = lsu_single_ecc_error_r & ~lsu_error_pkt_r.exc_valid & ~lsu_pkt_r.dma; assign lsu_error_pkt_r.inst_type = lsu_pkt_r.store; assign lsu_error_pkt_r.exc_type = ~misaligned_fault_r; assign lsu_error_pkt_r.mscause[3:0] = (lsu_double_ecc_error_r & ~misaligned_fault_r & ~access_fault_r) ? 4'h1 : exc_mscause_r[3:0]; assign lsu_error_pkt_r.addr[31:0] = lsu_addr_r[31:0]; assign lsu_fir_error[1:0] = fir_nondccm_access_error_r ? 2'b11 : (fir_dccm_access_error_r ? 2'b10 : ((lsu_pkt_r.fast_int & lsu_double_ecc_error_r) ? 2'b01 : 2'b00)); rvdff #(1) access_fault_rff (.din(access_fault_m), .dout(access_fault_r), .clk(lsu_c1_r_clk), .*); rvdff #(1) misaligned_fault_rff (.din(misaligned_fault_m), .dout(misaligned_fault_r), .clk(lsu_c1_r_clk), .*); rvdff #(4) exc_mscause_rff (.din(exc_mscause_m[3:0]), .dout(exc_mscause_r[3:0]), .clk(lsu_c1_r_clk), .*); rvdff #(1) fir_dccm_access_error_mff (.din(fir_dccm_access_error_m), .dout(fir_dccm_access_error_r), .clk(lsu_c1_r_clk), .*); rvdff #(1) fir_nondccm_access_error_mff (.din(fir_nondccm_access_error_m), .dout(fir_nondccm_access_error_r), .clk(lsu_c1_r_clk), .*); end else begin: L2U_Plus1_0 logic [1:0] lsu_fir_error_m; // Generate exception packet assign lsu_error_pkt_m.exc_valid = (access_fault_m | misaligned_fault_m | lsu_double_ecc_error_m) & lsu_pkt_m.valid & ~lsu_pkt_m.dma & ~lsu_pkt_m.fast_int & ~flush_m_up; assign lsu_error_pkt_m.single_ecc_error = lsu_single_ecc_error_m & ~lsu_error_pkt_m.exc_valid & ~lsu_pkt_m.dma; assign lsu_error_pkt_m.inst_type = lsu_pkt_m.store; assign lsu_error_pkt_m.exc_type = ~misaligned_fault_m; assign lsu_error_pkt_m.mscause[3:0] = (lsu_double_ecc_error_m & ~misaligned_fault_m & ~access_fault_m) ? 4'h1 : exc_mscause_m[3:0]; assign lsu_error_pkt_m.addr[31:0] = lsu_addr_m[31:0]; assign lsu_fir_error_m[1:0] = fir_nondccm_access_error_m ? 2'b11 : (fir_dccm_access_error_m ? 2'b10 : ((lsu_pkt_m.fast_int & lsu_double_ecc_error_m) ? 2'b01 : 2'b00)); rvdff #(1) lsu_exc_valid_rff (.*, .din(lsu_error_pkt_m.exc_valid), .dout(lsu_error_pkt_r.exc_valid), .clk(lsu_c2_r_clk)); rvdff #(1) lsu_single_ecc_error_rff(.*, .din(lsu_error_pkt_m.single_ecc_error), .dout(lsu_error_pkt_r.single_ecc_error), .clk(lsu_c2_r_clk)); rvdffe #($bits(el2_lsu_error_pkt_t)-2) lsu_error_pkt_rff (.*, .din(lsu_error_pkt_m[$bits(el2_lsu_error_pkt_t)-1:2]), .dout(lsu_error_pkt_r[$bits(el2_lsu_error_pkt_t)-1:2]), .en(lsu_error_pkt_m.exc_valid | lsu_error_pkt_m.single_ecc_error | clk_override)); rvdff #(2) lsu_fir_error_rff (.*, .din(lsu_fir_error_m[1:0]), .dout(lsu_fir_error[1:0]), .clk(lsu_c2_r_clk)); end //Create DMA packet always_comb begin dma_pkt_d = '0; dma_pkt_d.valid = dma_dccm_req; dma_pkt_d.dma = 1'b1; dma_pkt_d.store = dma_mem_write; dma_pkt_d.load = ~dma_mem_write; dma_pkt_d.by = (dma_mem_sz[2:0] == 3'b0); dma_pkt_d.half = (dma_mem_sz[2:0] == 3'b1); dma_pkt_d.word = (dma_mem_sz[2:0] == 3'b10); dma_pkt_d.dword = (dma_mem_sz[2:0] == 3'b11); end always_comb begin lsu_pkt_d = dec_lsu_valid_raw_d ? lsu_p : dma_pkt_d; lsu_pkt_m_in = lsu_pkt_d; lsu_pkt_r_in = lsu_pkt_m; lsu_pkt_d.valid = (lsu_p.valid & ~(flush_m_up & ~lsu_p.fast_int)) | dma_dccm_req; lsu_pkt_m_in.valid = lsu_pkt_d.valid & ~(flush_m_up & ~lsu_pkt_d.dma); lsu_pkt_r_in.valid = lsu_pkt_m.valid & ~(flush_m_up & ~lsu_pkt_m.dma) ; end // C2 clock for valid and C1 for other bits of packet rvdff #(1) lsu_pkt_vldmff (.*, .din(lsu_pkt_m_in.valid), .dout(lsu_pkt_m.valid), .clk(lsu_c2_m_clk)); rvdff #(1) lsu_pkt_vldrff (.*, .din(lsu_pkt_r_in.valid), .dout(lsu_pkt_r.valid), .clk(lsu_c2_r_clk)); rvdff #($bits(el2_lsu_pkt_t)-1) lsu_pkt_mff (.*, .din(lsu_pkt_m_in[$bits(el2_lsu_pkt_t)-1:1]), .dout(lsu_pkt_m[$bits(el2_lsu_pkt_t)-1:1]), .clk(lsu_c1_m_clk)); rvdff #($bits(el2_lsu_pkt_t)-1) lsu_pkt_rff (.*, .din(lsu_pkt_r_in[$bits(el2_lsu_pkt_t)-1:1]), .dout(lsu_pkt_r[$bits(el2_lsu_pkt_t)-1:1]), .clk(lsu_c1_r_clk)); if (pt.LOAD_TO_USE_PLUS1 == 1) begin: L2U1_Plus1_1 logic [31:0] lsu_ld_datafn_r, lsu_ld_datafn_corr_r; assign lsu_ld_datafn_r[31:0] = addr_external_r ? bus_read_data_r[31:0] : lsu_ld_data_r[31:0]; assign lsu_ld_datafn_corr_r[31:0] = addr_external_r ? bus_read_data_r[31:0] : lsu_ld_data_corr_r[31:0]; // this is really R stage signal assign lsu_result_m[31:0] = ({32{ lsu_pkt_r.unsign & lsu_pkt_r.by }} & {24'b0,lsu_ld_datafn_r[7:0]}) | ({32{ lsu_pkt_r.unsign & lsu_pkt_r.half}} & {16'b0,lsu_ld_datafn_r[15:0]}) | ({32{~lsu_pkt_r.unsign & lsu_pkt_r.by }} & {{24{ lsu_ld_datafn_r[7]}}, lsu_ld_datafn_r[7:0]}) | ({32{~lsu_pkt_r.unsign & lsu_pkt_r.half}} & {{16{ lsu_ld_datafn_r[15]}},lsu_ld_datafn_r[15:0]}) | ({32{lsu_pkt_r.word}} & lsu_ld_datafn_r[31:0]); // this signal is used for gpr update assign lsu_result_corr_r[31:0] = ({32{ lsu_pkt_r.unsign & lsu_pkt_r.by }} & {24'b0,lsu_ld_datafn_corr_r[7:0]}) | ({32{ lsu_pkt_r.unsign & lsu_pkt_r.half}} & {16'b0,lsu_ld_datafn_corr_r[15:0]}) | ({32{~lsu_pkt_r.unsign & lsu_pkt_r.by }} & {{24{ lsu_ld_datafn_corr_r[7]}}, lsu_ld_datafn_corr_r[7:0]}) | ({32{~lsu_pkt_r.unsign & lsu_pkt_r.half}} & {{16{ lsu_ld_datafn_corr_r[15]}},lsu_ld_datafn_corr_r[15:0]}) | ({32{lsu_pkt_r.word}} & lsu_ld_datafn_corr_r[31:0]); end else begin: L2U1_Plus1_0 // block: L2U1_Plus1_1 logic [31:0] lsu_ld_datafn_m, lsu_ld_datafn_corr_r; assign lsu_ld_datafn_m[31:0] = addr_external_m ? bus_read_data_m[31:0] : lsu_ld_data_m[31:0]; assign lsu_ld_datafn_corr_r[31:0] = addr_external_r ? bus_read_data_r[31:0] : lsu_ld_data_corr_r[31:0]; // this result must look at prior stores and merge them in assign lsu_result_m[31:0] = ({32{ lsu_pkt_m.unsign & lsu_pkt_m.by }} & {24'b0,lsu_ld_datafn_m[7:0]}) | ({32{ lsu_pkt_m.unsign & lsu_pkt_m.half}} & {16'b0,lsu_ld_datafn_m[15:0]}) | ({32{~lsu_pkt_m.unsign & lsu_pkt_m.by }} & {{24{ lsu_ld_datafn_m[7]}}, lsu_ld_datafn_m[7:0]}) | ({32{~lsu_pkt_m.unsign & lsu_pkt_m.half}} & {{16{ lsu_ld_datafn_m[15]}},lsu_ld_datafn_m[15:0]}) | ({32{lsu_pkt_m.word}} & lsu_ld_datafn_m[31:0]); // this signal is used for gpr update assign lsu_result_corr_r[31:0] = ({32{ lsu_pkt_r.unsign & lsu_pkt_r.by }} & {24'b0,lsu_ld_datafn_corr_r[7:0]}) | ({32{ lsu_pkt_r.unsign & lsu_pkt_r.half}} & {16'b0,lsu_ld_datafn_corr_r[15:0]}) | ({32{~lsu_pkt_r.unsign & lsu_pkt_r.by }} & {{24{ lsu_ld_datafn_corr_r[7]}}, lsu_ld_datafn_corr_r[7:0]}) | ({32{~lsu_pkt_r.unsign & lsu_pkt_r.half}} & {{16{ lsu_ld_datafn_corr_r[15]}},lsu_ld_datafn_corr_r[15:0]}) | ({32{lsu_pkt_r.word}} & lsu_ld_datafn_corr_r[31:0]); end // Fast interrupt address assign lsu_fir_addr[31:1] = lsu_ld_data_corr_r[31:1]; // absence load/store all 0's assign lsu_addr_d[31:0] = full_addr_d[31:0]; // Interrupt as a flush source allows the WB to occur assign lsu_commit_r = lsu_pkt_r.valid & (lsu_pkt_r.store | lsu_pkt_r.load) & ~flush_r & ~lsu_pkt_r.dma; assign dma_mem_wdata_shifted[63:0] = 64'(dma_mem_wdata[63:0] >> {dma_mem_addr[2:0], 3'b000}); // Shift the dma data to lower bits to make it consistent to lsu stores assign store_data_d[31:0] = dma_dccm_req ? dma_mem_wdata_shifted[31:0] : exu_lsu_rs2_d[31:0]; // Write to PIC still happens in r stage assign store_data_m_in[31:0] = (lsu_pkt_d.store_data_bypass_d) ? lsu_result_m[31:0] : store_data_d[31:0]; assign store_data_m[31:0] = (picm_mask_data_m[31:0] | {32{~addr_in_pic_m}}) & ((lsu_pkt_m.store_data_bypass_m) ? lsu_result_m[31:0] : store_data_pre_m[31:0]); rvdff #(32) sdmff (.*, .din(store_data_m_in[31:0]), .dout(store_data_pre_m[31:0]), .clk(lsu_store_c1_m_clk)); rvdff #(32) samff (.*, .din(lsu_addr_d[31:0]), .dout(lsu_addr_m[31:0]), .clk(lsu_c1_m_clk)); rvdff #(32) sarff (.*, .din(lsu_addr_m[31:0]), .dout(lsu_addr_r[31:0]), .clk(lsu_c1_r_clk)); assign end_addr_m[31:3] = ldst_dual_m ? end_addr_pre_m[31:3] : lsu_addr_m[31:3]; // This is for power saving assign end_addr_r[31:3] = ldst_dual_r ? end_addr_pre_r[31:3] : lsu_addr_r[31:3]; // This is for power saving rvdffe #(29) end_addr_hi_mff (.*, .din(end_addr_d[31:3]), .dout(end_addr_pre_m[31:3]), .en((lsu_pkt_d.valid & ldst_dual_d) | clk_override)); rvdffe #(29) end_addr_hi_rff (.*, .din(end_addr_m[31:3]), .dout(end_addr_pre_r[31:3]), .en((lsu_pkt_m.valid & ldst_dual_m) | clk_override)); rvdff #(3) end_addr_lo_mff (.*, .din(end_addr_d[2:0]), .dout(end_addr_m[2:0]), .clk(lsu_c1_m_clk)); rvdff #(3) end_addr_lo_rff (.*, .din(end_addr_m[2:0]), .dout(end_addr_r[2:0]), .clk(lsu_c1_r_clk)); rvdff #(1) addr_in_dccm_mff(.din(addr_in_dccm_d), .dout(addr_in_dccm_m), .clk(lsu_c1_m_clk), .*); rvdff #(1) addr_in_dccm_rff(.din(addr_in_dccm_m), .dout(addr_in_dccm_r), .clk(lsu_c1_r_clk), .*); rvdff #(1) addr_in_pic_mff(.din(addr_in_pic_d), .dout(addr_in_pic_m), .clk(lsu_c1_m_clk), .*); rvdff #(1) addr_in_pic_rff(.din(addr_in_pic_m), .dout(addr_in_pic_r), .clk(lsu_c1_r_clk), .*); rvdff #(1) addr_external_mff(.din(addr_external_d), .dout(addr_external_m), .clk(lsu_c1_m_clk), .*); rvdff #(1) addr_external_rff(.din(addr_external_m), .dout(addr_external_r), .clk(lsu_c1_r_clk), .*); rvdff #(1) access_fault_mff (.din(access_fault_d), .dout(access_fault_m), .clk(lsu_c1_m_clk), .*); rvdff #(1) misaligned_fault_mff (.din(misaligned_fault_d), .dout(misaligned_fault_m), .clk(lsu_c1_m_clk), .*); rvdff #(4) exc_mscause_mff (.din(exc_mscause_d[3:0]), .dout(exc_mscause_m[3:0]), .clk(lsu_c1_m_clk), .*); rvdff #(1) fir_dccm_access_error_mff (.din(fir_dccm_access_error_d), .dout(fir_dccm_access_error_m), .clk(lsu_c1_m_clk), .*); rvdff #(1) fir_nondccm_access_error_mff (.din(fir_nondccm_access_error_d), .dout(fir_nondccm_access_error_m), .clk(lsu_c1_m_clk), .*); rvdffe #(32) bus_read_data_r_ff (.*, .din(bus_read_data_m[31:0]), .dout(bus_read_data_r[31:0]), .en(addr_external_m | clk_override)); endmodule ================================================ FILE: design/lsu/el2_lsu_stbuf.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: Store Buffer // Comments: Dual writes and single drain // // // DC1 -> DC2 -> DC3 -> DC4 (Commit) // // //******************************************************************************** module el2_lsu_stbuf import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // core clock input logic rst_l, // reset input logic lsu_stbuf_c1_clk, // stbuf clock input logic lsu_free_c2_clk, // free clk // Store Buffer input input logic store_stbuf_reqvld_r, // core instruction goes to stbuf input logic lsu_commit_r, // lsu commits input logic dec_lsu_valid_raw_d, // Speculative decode valid input logic [pt.DCCM_DATA_WIDTH-1:0] store_data_hi_r, // merged data from the dccm for stores. This is used for fwding input logic [pt.DCCM_DATA_WIDTH-1:0] store_data_lo_r, // merged data from the dccm for stores. This is used for fwding input logic [pt.DCCM_DATA_WIDTH-1:0] store_datafn_hi_r, // merged data from the dccm for stores input logic [pt.DCCM_DATA_WIDTH-1:0] store_datafn_lo_r, // merged data from the dccm for stores // Store Buffer output output logic stbuf_reqvld_any, // stbuf is draining output logic stbuf_reqvld_flushed_any, // Top entry is flushed output logic [pt.LSU_SB_BITS-1:0] stbuf_addr_any, // address output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_data_any, // stbuf data input logic lsu_stbuf_commit_any, // pop the stbuf as it commite output logic lsu_stbuf_full_any, // stbuf is full output logic lsu_stbuf_empty_any, // stbuf is empty output logic ldst_stbuf_reqvld_r, // needed for clocking input logic [pt.LSU_SB_BITS-1:0] lsu_addr_d, // lsu address D-stage input logic [31:0] lsu_addr_m, // lsu address M-stage input logic [31:0] lsu_addr_r, // lsu address R-stage input logic [pt.LSU_SB_BITS-1:0] end_addr_d, // lsu end address D-stage - needed to check unaligned input logic [31:0] end_addr_m, // lsu end address M-stage - needed to check unaligned input logic [31:0] end_addr_r, // lsu end address R-stage - needed to check unaligned input logic ldst_dual_d, ldst_dual_m, ldst_dual_r, input logic addr_in_dccm_m, // address is in dccm input logic addr_in_dccm_r, // address is in dccm // Forwarding signals input logic lsu_cmpen_m, // needed for forwarding stbuf - load input el2_lsu_pkt_t lsu_pkt_m, // LSU packet M-stage input el2_lsu_pkt_t lsu_pkt_r, // LSU packet R-stage output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_m, // stbuf data output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_m, // stbuf data output logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_m, // stbuf data output logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_m, // stbuf data // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // Scan mode /*pragma coverage on*/ ); localparam DEPTH = pt.LSU_STBUF_DEPTH; localparam DATA_WIDTH = pt.DCCM_DATA_WIDTH; localparam BYTE_WIDTH = pt.DCCM_BYTE_WIDTH; localparam DEPTH_LOG2 = $clog2(DEPTH); // These are the fields in the store queue logic [DEPTH-1:0] stbuf_vld; logic [DEPTH-1:0] stbuf_dma_kill; logic [DEPTH-1:0][pt.LSU_SB_BITS-1:0] stbuf_addr; logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_byteen; logic [DEPTH-1:0][DATA_WIDTH-1:0] stbuf_data; logic [DEPTH-1:0] sel_lo; logic [DEPTH-1:0] stbuf_wr_en; logic [DEPTH-1:0] stbuf_dma_kill_en; logic [DEPTH-1:0] stbuf_reset; logic [DEPTH-1:0][pt.LSU_SB_BITS-1:0] stbuf_addrin; logic [DEPTH-1:0][DATA_WIDTH-1:0] stbuf_datain; logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_byteenin; logic [7:0] store_byteen_ext_r; logic [BYTE_WIDTH-1:0] store_byteen_hi_r; logic [BYTE_WIDTH-1:0] store_byteen_lo_r; logic WrPtrEn, RdPtrEn; logic [DEPTH_LOG2-1:0] WrPtr, RdPtr; logic [DEPTH_LOG2-1:0] NxtWrPtr, NxtRdPtr; logic [DEPTH_LOG2-1:0] WrPtrPlus1, WrPtrPlus2, RdPtrPlus1; logic dual_stbuf_write_r; logic isdccmst_m, isdccmst_r; logic [3:0] stbuf_numvld_any, stbuf_specvld_any; logic [1:0] stbuf_specvld_m, stbuf_specvld_r; logic [pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] cmpaddr_hi_m, cmpaddr_lo_m; // variables to detect matching from the store queue logic [DEPTH-1:0] stbuf_match_hi, stbuf_match_lo; logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_fwdbyteenvec_hi, stbuf_fwdbyteenvec_lo; logic [DATA_WIDTH-1:0] stbuf_fwddata_hi_pre_m, stbuf_fwddata_lo_pre_m; logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_pre_m, stbuf_fwdbyteen_lo_pre_m; // logic to detect matching from the pipe - needed for store - load forwarding logic [BYTE_WIDTH-1:0] ld_byte_rhit_lo_lo, ld_byte_rhit_hi_lo, ld_byte_rhit_lo_hi, ld_byte_rhit_hi_hi; logic ld_addr_rhit_lo_lo, ld_addr_rhit_hi_lo, ld_addr_rhit_lo_hi, ld_addr_rhit_hi_hi; logic [BYTE_WIDTH-1:0] ld_byte_hit_lo, ld_byte_rhit_lo; logic [BYTE_WIDTH-1:0] ld_byte_hit_hi, ld_byte_rhit_hi; logic [BYTE_WIDTH-1:0] ldst_byteen_hi_r; logic [BYTE_WIDTH-1:0] ldst_byteen_lo_r; // byte_en flowing down logic [7:0] ldst_byteen_r; logic [7:0] ldst_byteen_ext_r; // fwd data through the pipe logic [31:0] ld_fwddata_rpipe_lo; logic [31:0] ld_fwddata_rpipe_hi; // coalescing signals logic [DEPTH-1:0] store_matchvec_lo_r, store_matchvec_hi_r; logic store_coalesce_lo_r, store_coalesce_hi_r; //---------------------------------------- // Logic starts here //---------------------------------------- // Create high/low byte enables assign store_byteen_ext_r[7:0] = ldst_byteen_r[7:0] << lsu_addr_r[1:0]; assign store_byteen_hi_r[BYTE_WIDTH-1:0] = store_byteen_ext_r[7:4] & {4{lsu_pkt_r.store}}; assign store_byteen_lo_r[BYTE_WIDTH-1:0] = store_byteen_ext_r[3:0] & {4{lsu_pkt_r.store}}; assign RdPtrPlus1[DEPTH_LOG2-1:0] = RdPtr[DEPTH_LOG2-1:0] + 1'b1; assign WrPtrPlus1[DEPTH_LOG2-1:0] = WrPtr[DEPTH_LOG2-1:0] + 1'b1; assign WrPtrPlus2[DEPTH_LOG2-1:0] = WrPtr[DEPTH_LOG2-1:0] + 2'b10; // ecc error on both hi/lo assign dual_stbuf_write_r = ldst_dual_r & store_stbuf_reqvld_r; assign ldst_stbuf_reqvld_r = ((lsu_commit_r | lsu_pkt_r.dma) & store_stbuf_reqvld_r); // Store Buffer coalescing for (genvar i=0; i= DEPTH) : (stbuf_specvld_any[3:0] >= (DEPTH-1)); assign lsu_stbuf_empty_any = (stbuf_numvld_any[3:0] == 4'b0); // Load forwarding logic from the store queue assign cmpaddr_hi_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = end_addr_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]; assign cmpaddr_lo_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = lsu_addr_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]; always_comb begin: GenLdFwd stbuf_fwdbyteen_hi_pre_m[BYTE_WIDTH-1:0] = '0; stbuf_fwdbyteen_lo_pre_m[BYTE_WIDTH-1:0] = '0; for (int i=0; i (lsu_pkt_r.valid & lsu_pkt_r.store & addr_in_dccm_r); endproperty assert_stbuf_wren_store_dccm: assert property (stbuf_wren_store_dccm) else $display("Illegal store buffer write"); `endif endmodule ================================================ FILE: design/lsu/el2_lsu_trigger.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** // $Id$ // // // Owner: // Function: LSU Trigger logic // Comments: // //******************************************************************************** module el2_lsu_trigger import el2_pkg::*; #( `include "el2_param.vh" )( input el2_trigger_pkt_t [3:0] trigger_pkt_any, // trigger packet from dec input el2_lsu_pkt_t lsu_pkt_m, // lsu packet input logic [31:0] lsu_addr_m, // address input logic [31:0] store_data_m, // store data output logic [3:0] lsu_trigger_match_m // match result ); logic trigger_enable; logic [3:0][31:0] lsu_match_data; logic [3:0] lsu_trigger_data_match; logic [31:0] store_data_trigger_m; logic [31:0] ldst_addr_trigger_m; // Generate the trigger enable (This is for power) always_comb begin trigger_enable = 1'b0; for (int i=0; i<4; i++) begin trigger_enable |= trigger_pkt_any[i].m; end end assign store_data_trigger_m[31:0] = {({16{lsu_pkt_m.word}} & store_data_m[31:16]),({8{(lsu_pkt_m.half | lsu_pkt_m.word)}} & store_data_m[15:8]), store_data_m[7:0]} & {32{trigger_enable}}; assign ldst_addr_trigger_m[31:0] = lsu_addr_m[31:0] & {32{trigger_enable}}; for (genvar i=0; i<4; i++) begin : genblock assign lsu_match_data[i][31:0] = ({32{~trigger_pkt_any[i].select}} & ldst_addr_trigger_m[31:0]) | ({32{trigger_pkt_any[i].select & trigger_pkt_any[i].store}} & store_data_trigger_m[31:0]); rvmaskandmatch trigger_match (.mask(trigger_pkt_any[i].tdata2[31:0]), .data(lsu_match_data[i][31:0]), .masken(trigger_pkt_any[i].match), .match(lsu_trigger_data_match[i])); assign lsu_trigger_match_m[i] = lsu_pkt_m.valid & ~lsu_pkt_m.dma & trigger_enable & ((trigger_pkt_any[i].store & lsu_pkt_m.store) | (trigger_pkt_any[i].load & lsu_pkt_m.load & ~trigger_pkt_any[i].select)) & lsu_trigger_data_match[i]; end endmodule // el2_lsu_trigger ================================================ FILE: docs/Makefile ================================================ SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = source BUILDDIR = build # Catch-all target: route all unknown targets to Sphinx using the "make mode" option. # $(O) is meant as a shortcut for $(SPHINXOPTS). %: @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) @bash update_styles.sh "$(BUILDDIR)" ================================================ FILE: docs/dashboard-styles/gcov.css ================================================ /* All views: initial background and text color */ @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); body { color: #E9EBFA; background-color: #0E1116; padding: 0; margin: 0; font-family: 'Roboto', sans-serif; box-sizing: border-box; } /* * { } */ /* All views: standard link format*/ a:link { color: #00D0C9; text-decoration: underline; font-family: 'Roboto', sans-serif; } /* All views: standard link - visited format */ a:visited { color: #E9EBFA; text-decoration: underline; } /* All views: standard link - activated format */ a:active { color: #00D0C9; color: #E9EBFA; text-decoration: underline; } th { border: 1px solid; } td { color: #E9EBFA; } body > table:nth-child(1) > tbody > tr:nth-child(3) { height: 300px; } body > center > table td:not(.coverBarOutline){ border: 1px solid #31363C; } body > center > table > tbody > tr:nth-child(1) { display: none; } body>table:nth-child(1)>tbody>tr:nth-child(3) { display: flex; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td { align-self: center; padding: 0 95px; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(1) > td.headerValue { font-size: 35px; } body>table:nth-child(1)>tbody>tr:nth-child(3)>td>table>tbody>tr:nth-child(1)>td.headerItem { font-weight: 300; font-size: 35px; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(1) > td.headerValue { font-size: 35px; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(2) > td.headerItem { font-size: 22px; font-weight: 300; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(2) > td.headerValue { font-size: 22px; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(3) > td.headerItem { font-size: 22px; font-weight: 300; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(3) > td.headerValue { font-size: 22px; } body > table:nth-child(1) > tbody > tr:nth-child(1) { position: relative; } body > table:nth-child(1) > tbody > tr:nth-child(1) > td::before { content: url(../../../_static/white.svg); position: absolute; left: 95px; transform: translateY(-15%); } table { border-collapse: collapse; width: 100%; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody { padding: 0 50px; } body > center > table > tbody tr { width: 19px; } /* All views: main title format */ td.title { background-color: #25292E; color: #DFE1F1; text-align: center; padding-bottom: 10px; font-size: 20px; font-weight: bold; padding: 20px 0; } /* All views: header item format */ td.headerItem { text-align: right; padding-right: 6px; font-weight: bold; white-space: nowrap; } /* All views: header item value format */ td.headerValue { text-align: left; color: #00D0C9; font-weight: bold; white-space: nowrap; } body > table:nth-child(1) > tbody > tr:nth-child(3) > td > table > tbody > tr:nth-child(1) > td:nth-child(5)::after { content: ' '; width: 10px; } /* All views: header item coverage table heading */ td.headerCovTableHead { color: #DFE1F1; text-align: center; padding-right: 6px; padding-left: 6px; padding-bottom: 0px; font-size: 14px; white-space: nowrap; } /* All views: header item coverage table entry */ td.headerCovTableEntry { text-align: right; color: #DFE1F1; text-align: center; background-color: #31363C; font-weight: bold; white-space: nowrap; padding-left: 12px; padding-right: 4px; } /* All views: header item coverage table entry for high coverage rate */ td.headerCovTableEntryHi { text-align: right; color: #000000; font-weight: bold; white-space: nowrap; padding-left: 12px; padding-right: 4px; background-color: #2FC36E; } /* All views: header item coverage table entry for medium coverage rate */ td.headerCovTableEntryMed { text-align: right; color: #000000; font-weight: bold; white-space: nowrap; padding-left: 12px; padding-right: 4px; background-color: #EFAC0A; } /* All views: header item coverage table entry for ow coverage rate */ td.headerCovTableEntryLo { text-align: right; color: #DFE1F1; text-align: center; font-weight: bold; white-space: nowrap; padding-left: 12px; padding-right: 4px; background-color: #F21E08; } /* All views: header legend value for legend entry */ td.headerValueLeg { text-align: left; color: #000000; font-size: 80%; white-space: nowrap; padding-top: 4px; } body>table:nth-child(1)>tbody>tr:nth-child(2)>td { display: none; } /* All views: color of horizontal ruler */ td.ruler > img { height: 1px ; width: 100% ; background-color: rgba(255, 255, 255, 0.3); aspect-ratio: 1 / 1; } /* All views: version string format */ td.versionInfo { text-align: center; padding-top: 35px; font-style: italic; } td.versionInfo > a { color: #00D0C9; } /* Directory view/File view (all)/Test case descriptions: table headline format */ td.tableHead { text-align: center; color: #ffffff; background-color: #0E1116; font-size: 16px; font-weight: bold; white-space: nowrap; padding-left: 4px; padding-right: 4px; } span.tableHeadSort { padding-right: 4px; } td { align-items: center; } center { padding: 95px; } /* Directory view/File view (all): filename entry format */ td.coverFile { text-align: left; padding-left: 10px; padding-right: 20px; color: #E9EBFA; background-color: #0E1116; font-family: monospace; } /* Directory view/File view (all): bar-graph entry format*/ td.coverBar { background-color: #0E1116; } /* Directory view/File view (all): bar-graph outline color */ td.coverBarOutline { background-color: #0E1116; display: flex; justify-content: center; } /* Directory view/File view (all): percentage entry for files with high coverage rate */ td.coverPerHi { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #0E1116; color: #2FC36E; font-weight: bold; } /* Directory view/File view (all): line count entry for files with high coverage rate */ td.coverNumHi { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #0E1116; white-space: nowrap; } /* Directory view/File view (all): percentage entry for files with medium coverage rate */ td.coverPerMed { text-align: right; padding-left: 10px; padding-right: 10px; color: #EFAC0A; background-color: #0E1116; font-weight: bold; } /* Directory view/File view (all): line count entry for files with medium coverage rate */ td.coverNumMed { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #0E1116; white-space: nowrap; } /* Directory view/File view (all): percentage entry for files with low coverage rate */ td.coverPerLo { text-align: right; padding-left: 10px; padding-right: 10px; color: #F21E08; background-color: #0E1116; font-weight: bold; } /* Directory view/File view (all): line count entry for files with low coverage rate */ td.coverNumLo { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #0E1116; white-space: nowrap; } /* File view (all): "show/hide details" link format */ a.detail:link { color: #B8D0FF; font-size:80%; } /* File view (all): "show/hide details" link - visited format */ a.detail:visited { color: #B8D0FF; font-size:80%; } /* File view (all): "show/hide details" link - activated format */ a.detail:active { color: #ffffff; font-size:80%; } /* File view (detail): test name entry */ td.testName { text-align: right; padding-right: 10px; background-color: #dae7fe; } /* File view (detail): test percentage entry */ td.testPer { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #dae7fe; } /* File view (detail): test lines count entry */ td.testNum { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #dae7fe; } /* Test case descriptions: test name format*/ dt { font-weight: bold; } /* Test case descriptions: description table body */ td.testDescription { padding-top: 10px; padding-left: 30px; padding-bottom: 10px; padding-right: 30px; background-color: #dae7fe; } /* Source code view: function entry */ td.coverFn { text-align: left; padding-left: 10px; padding-right: 20px; color: #284fa8; background-color: #dae7fe; font-family: monospace; } /* Source code view: function entry zero count*/ td.coverFnLo { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #ff0000; font-weight: bold; } /* Source code view: function entry nonzero count*/ td.coverFnHi { text-align: right; padding-left: 10px; padding-right: 10px; background-color: #dae7fe; font-weight: bold; } /* Source code view: source code format */ pre.source { font-family: monospace; white-space: pre; margin-top: 2px; } /* Source code view: line number format */ span.lineNum { background-color: #efe383; } /* Source code view: format for lines which were executed */ td.lineCov, span.lineCov { background-color: #cad7fe; } /* Source code view: format for Cov legend */ span.coverLegendCov { padding-left: 10px; padding-right: 10px; padding-bottom: 2px; background-color: #cad7fe; } /* Source code view: format for lines which were not executed */ td.lineNoCov, span.lineNoCov { background-color: #ff6230; } /* Source code view: format for NoCov legend */ span.coverLegendNoCov { padding-left: 10px; padding-right: 10px; padding-bottom: 2px; background-color: #ff6230; } /* Source code view (function table): standard link - visited format */ td.lineNoCov > a:visited, td.lineCov > a:visited { color: #000000; text-decoration: underline; } /* Source code view: format for lines which were executed only in a previous version */ span.lineDiffCov { background-color: #b5f7af; } /* Source code view: format for branches which were executed * and taken */ span.branchCov { background-color: #cad7fe; } /* Source code view: format for branches which were executed * but not taken */ span.branchNoCov { background-color: #ff6230; } /* Source code view: format for branches which were not executed */ span.branchNoExec { background-color: #ff6230; } /* Source code view: format for the source code heading line */ pre.sourceHeading { white-space: pre; font-family: monospace; font-weight: bold; margin: 0px; } /* All views: header legend value for low rate */ td.headerValueLegL { text-align: center; white-space: nowrap; padding-left: 4px; padding-right: 2px; background-color: #ff0000; font-size: 80%; } /* All views: header legend value for med rate */ td.headerValueLegM { text-align: center; white-space: nowrap; padding-left: 2px; padding-right: 2px; background-color: #ffea20; font-size: 80%; } /* All views: header legend value for hi rate */ td.headerValueLegH { text-align: center; white-space: nowrap; padding-left: 2px; padding-right: 4px; background-color: #a7fc9d; font-size: 80%; } /* All views except source code view: legend format for low coverage */ span.coverLegendCovLo { padding-left: 10px; padding-right: 10px; padding-top: 2px; background-color: #ff0000; } /* All views except source code view: legend format for med coverage */ span.coverLegendCovMed { padding-left: 10px; padding-right: 10px; padding-top: 2px; background-color: #ffea20; } /* All views except source code view: legend format for hi coverage */ span.coverLegendCovHi { padding-left: 10px; padding-right: 10px; padding-top: 2px; background-color: #a7fc9d; } ================================================ FILE: docs/dashboard-styles/main.css ================================================ [data-md-color-scheme="slate"] { --md-hue: 218; --md-default-bg-color: hsla(var(--md-hue), 22%, 7%, 1); } [data-md-color-primary="teal"] { --md-primary-fg-color: #25292e; } [data-md-color-scheme="slate"][data-md-color-primary="teal"] { --md-typeset-a-color: #00d0c9; } .md-social { display: none; } .md-header__option { display: none; } ================================================ FILE: docs/requirements.txt ================================================ Sphinx>=8.0.2,<9 https://github.com/antmicro/antmicro-sphinx-utils/archive/main.zip ================================================ FILE: docs/source/adaptations.md ================================================ # Standard RISC-V CSRs with Core-Specific Adaptations A summary of standard RISC-V control/status registers in CSR space with platform-specific adaptations: * [](adaptations.md#machine-interrupt-enable-mie-and-machine-interrupt-pending-mip-registers) * [](adaptations.md#machine-cause-register-mcause) * [](adaptations.md#machine-hardware-thread-id-register-mhartid) All reserved and unused bits in these control/status registers must be hardwired to '0'. Unless otherwise noted, all read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. ## Machine Interrupt Enable (mie) and Machine Interrupt Pending (mip) Registers The standard RISC-V `mie` and `mip` registers hold the machine interrupt enable and interrupt pending bits, respectively. Since VeeR EL2 only supports machine and user mode, all supervisor-specific bits are not implemented. In addition, the `mie/mip` registers also host the platform-specific local interrupt enable/pending bits (shown with a gray background in {numref}`tab-machine-interrupt-enable-register` and {numref}`tab-machine-interrupt-pending-register` below). The `mie` register is a standard read/write CSR. :::{list-table} Machine Interrupt Enable Register (mie, at CSR 0x304) :name: tab-machine-interrupt-enable-register :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31 - Reserved - R - 0 * - mceie - 30 - Correctable error local interrupt enable - R/W - 0 * - mitie0 - 29 - Internal timer 0 local interrupt enable - R/W - 0 * - mitie1 - 28 - Internal timer 1 local interrupt enable - R/W - 0 * - Reserved - 27:12 - Reserved - R - 0 * - meie - 11 - Machine external interrupt enable - R/W - 0 * - Reserved - 10:8 - Reserved - R - 0 * - mtie - 7 - Machine timer interrupt enable - R/W - 0 * - Reserved - 6:4 - Reserved - R - 0 * - msie - 3 - Machine software interrupt enable - R/W - 0 * - Reserved - 2:0 - Reserved - R - 0 ::: The `mip` register is a standard read/write CSR. :::{note} All M-mode interrupt pending bits of the read/write `mip` register are read-only. ::: :::{list-table} Machine Interrupt Pending Register (mip, at CSR 0x344) :name: tab-machine-interrupt-pending-register :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31 - Reserved - R - 0 * - mceip - 30 - Correctable error local interrupt pending - R - 0 * - mitip0 - 29 - Internal timer 0 local interrupt pending - R - 0 * - mitip1 - 28 - Internal timer 1 local interrupt pending - R - 0 * - Reserved - 27:12 - Reserved - R - 0 * - meip - 11 - Machine external interrupt pending - R - 0 * - Reserved - 10:8 - Reserved - R - 0 * - mtip - 7 - Machine timer interrupt pending - R - 0 * - Reserved - 6:4 - Reserved - R - 0 * - msip - 3 - Machine software interrupt pending - R - 0 * - Reserved - 2:0 - Reserved - R - 0 ::: ## Machine Cause Register (mcause) The standard RISC-V mcause register indicates the cause for a trap as shown in {numref}`tab-machine-cause-register`, including standard exceptions/interrupts, platform-specific local interrupts (with light gray background), and NMI causes (with dark gray background). Additional trap information is provided in the mscause register, see [](memory-map.md#machine-secondary-cause-register-mscause) which allows the determination of the exact cause of a trap for cases where multiple, different conditions share a single trap code. The `mcause` register has WLRL (Write Legal value, Read Legal value) behavior. This register is a standard read/write CSR. :::{list-table} Machine Cause Register (mcause, at CSR 0x342) :name: tab-machine-cause-register :header-rows: 1 * - **Type** - **Trap Code** - **Value mcause[31:0]** - **Description** - **Section(s)** * - **NMI** - N/A - 0x0000_0000 - NMI pin assertion - [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - **Exception** - 1 - 0x0000_0001 - Instruction access fault - [](memory-map.md#unmapped-addresses), [](memory-map.md#uncorrectable-ecc-errors), and [](error-protection.md#error-detection-and-handling) * - - 2 - 0x0000_0002 - Illegal instruction - \- * - - 3 - 0x0000_0003 - Breakpoint - \- * - - 4 - 0x0000_0004 - Load address misaligned - [](memory-map.md#misaligned-accesses) * - - 5 - 0x0000_0005 - Load access fault - [](memory-map.md#unmapped-addresses), [](memory-map.md#uncorrectable-ecc-errors), and [](error-protection.md#error-detection-and-handling) * - - 6 - 0x0000_0006 - Store/AMO address misaligned - [](memory-map.md#misaligned-accesses) * - - 7 - 0x0000_0007 - Store/AMO access fault - [](memory-map.md#unmapped-addresses), [](memory-map.md#uncorrectable-ecc-errors), and [](error-protection.md#error-detection-and-handling) * - - 11 - 0x0000_000B - Environment call from M-mode - \- * - **Interrupt** - 3 - 0x8000_0003 - Machine software interrupt - [](memory-map.md#software-interrupts) * - - 7 - 0x8000_0007 - Machine timer [^fn-adaptations-1] interrupt - \- * - - 11 - 0x8000_000B - Machine external interrupt - [](interrupts.md) * - - 28 - 0x8000_001C - Machine internal timer 1 local interrupt - [](timers.md#internal-timer-local-interrupts) * - - 29 - 0x8000_001D - Machine internal timer 0 local interrupt - [](timers.md#internal-timer-local-interrupts) * - - 30 - 0x8000_001E - Machine correctable error local interrupt - [](memory-map.md#correctable-error-local-interrupt) * - **NMI** - N/A - 0xF000_0000 - Machine D-bus store error NMI - [](memory-map.md#imprecise-bus-error-non-maskable-interrupt) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - - N/A - 0xF000_0001 - Machine D-bus non-blocking load error NMI - [](memory-map.md#imprecise-bus-error-non-maskable-interrupt) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - - N/A - 0xF000_1000 - Machine Fast Interrupt double-bit ECC error NMI - [](interrupts.md#fast-interrupt-redirect) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - - N/A - 0xF000_1001 - Machine Fast Interrupt DCCM region access error NMI - [](interrupts.md#fast-interrupt-redirect) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - - N/A - 0xF000_1002 - Machine Fast Interrupt non-DCCM region NMI - [](interrupts.md#fast-interrupt-redirect) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) ::: [^fn-adaptations-1]: Core external timer :::{note} All other values are reserved. ::: ## Machine Hardware Thread ID Register (mhartid) The standard RISC-V `mhartid` register provides the integer ID of the hardware thread running the code. Hart IDs must be unique. Hart IDs might not necessarily be numbered contiguously in a multiprocessor system, but at least one hart must have a hart ID of zero. :::{note} In certain cases, it must be ensured that exactly one hart runs some code (e.g., at reset), hence the requirement for one hart to have a known hart ID of zero. ::: The `mhartid` register is split into two fixed-sized fields. The SoC must provide a hardwired core ID on the `core_id[31:4]` bus. The value provided on that bus sources the `mhartid` register's *coreid* field. If the SoC hosts more than one RISC-V core, each core must have its own unique `core_id` value. Each hardware thread of the core has a unique, hardwired thread ID which is reflected in the `mhartid` register's *hartid* field starting at 0x0 up to 0xF. VeeR EL2 implements a single hardware thread with thread ID 0x0. This register is a standard read-only CSR. :::{list-table} Machine Hardware Thread ID Register (mhartid, at CSR 0xF14) :name: tab-machine-hw-thread-id-register :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - coreid - 31:4 - Core ID of this VeeR EL2 - R - `core_id[31:4]` bus value (see {numref}`tab-core-complex-signals`) * - hartid - 3:0 - Hardwired per-core hart ID: 0x0: thread 0 (master thread) - R - 0x0 ::: ================================================ FILE: docs/source/build-args.md ================================================ # Build Arguments ## Memory Protection Build Arguments ### Memory Protection Build Argument Rules The rules for valid memory protection address (INST/DATA_ACCESS_ADDRx) and mask (INST/DATA_ACCESS_MASKx) build arguments are: * INST/DATA_ACCESS_ADDRx must be 64B-aligned (i.e., 6 least significant bits must be '0') * INST/DATA_ACCESS_MASKx must be an integer multiple of 64B minus 1 (i.e., 6 least significant bits must be '1') * For INST/DATA_ACCESS_MASKx, all '0' bits (if any) must be left-justified and all '1' bits must be right-justified * No bit in INST/DATA_ACCESS_ADDRx may be '1' if the corresponding bit in INST/DATA_ACCESS_MASKx is also '1' (i.e., for each bit position, at most one of the bits in INST/DATA_ACCESS_ADDRx and INST/DATA_ACCESS_MASKx may be '1') ### Memory Protection Build Arguments * **Instructions** * Instruction Access Window *x* (*x* = 0..7) * Enable (INST_ACCESS_ENABLEx): 0,1 *(0 = window disabled; 1 = window enabled)* * Base address (INST_ACCESS_ADDRx): 0x0000_0000..0xFFFF_FFC0, *see [](build-args.md#memory-protection-build-argument-rules)* * Mask (INST_ACCESS_MASKx): 0x0000_003F..0xFFFF_FFFF, *see [](build-args.md#memory-protection-build-argument-rules)* * **Data** * Data Access Window x (x = 0..7) * Enable (DATA_ACCESS_ENABLEx): 0,1 *(0 = window disabled; 1 = window enabled)* * Base address (DATA_ACCESS_ADDRx): 0x0000_0000..0xFFFF_FFC0, *see [](build-args.md#memory-protection-build-argument-rules)* * Mask (DATA_ACCESS_MASKx): 0x0000_003F..0xFFFF_FFFF, *see [](build-args.md#memory-protection-build-argument-rules)* ## Core Memory-Related Build Arguments ### Core Memories and Memory-Mapped Register Blocks Alignment Rules Placement of VeeR EL2's core memories and memory-mapped register blocks in the 32-bit address range is very flexible. Each memory or register block may be assigned to any region and within the region's 28-bit address range to any start address on a naturally aligned power-of-two address boundary relative to its own size (i.e., *start_address* = *n × size*, whereas n is a positive integer number). For example, the start address of an 8KB-sized DCCM may be 0x0000_0000, 0x0000_2000, 0x0000_4000, 0x0000_6000, etc. A memory or register block with a non-power-of-two size must be aligned to the next bigger power-of-two size. For example, the starting address of a 48KB-sized DCCM must aligned to a 64KB boundary, i.e., it may be 0x0000_0000, 0x0001_0000, 0x0002_0000, 0x0003_0000, etc. Also, no two memories or register blocks may overlap each other, and no memory or register block may cross a region boundary. The start address of the memory or register block is specified with an offset relative to the start address of the region. This offset must follow the rules described above. ### Memory-Related Build Arguments * **ICCM** * Enable (RV_ICCM_ENABLE): 0, 1 *(0 = no ICCM; 1 = ICCM enabled)* * Region (RV_ICCM_REGION): 0..15 * Offset (RV_ICCM_OFFSET): *offset in bytes from start of region satisfying rules in [](build-args.md#core-memories-and-memory-mapped-register-blocks-alignment-rules)* * Size (RV_ICCM_SIZE): 4, 8, 16, 32, 64, 128, 256, 512 *(in KB)* * **DCCM** * Region (RV_DCCM_REGION): 0..15 * Offset (RV_DCCM_OFFSET): *offset in bytes from start of region satisfying rules in [](build-args.md#core-memories-and-memory-mapped-register-blocks-alignment-rules)* * Size (RV_DCCM_SIZE): 4, 8, 16, 32, 48, 64, 128, 256, 512 *(in KB)* * **I-Cache** * Enable (RV_ICACHE_ENABLE): 0, 1 *(0 = no I-cache; 1 = I-cache enabled)* * Size (RV_ICACHE_SIZE): 16, 32, 64, 128, 256 *(in KB)* * Protection (RV_ICACHE_ECC): 0, 1 *(0 = parity; 1 = ECC)* * **PIC Memory-mapped Control Registers** * Region (RV_PIC_REGION): 0..15 * Offset (RV_PIC_OFFSET): *offset in bytes from start of region satisfying rules in [](build-args.md#core-memories-and-memory-mapped-register-blocks-alignment-rules)* * Size (RV_PIC_SIZE): 32, 64, 128, 256 *(in KB)* ================================================ FILE: docs/source/cache.md ================================================ # Cache Control This chapter describes the features to control the VeeR EL2 core's instruction cache (I-cache). ## Features The VeeR EL2's I-cache control features are: * Flushing the I-cache * Capability to enable/disable I-cache * Diagnostic access to data, tag, and status information of the I-cache :::{note} The I-cache is an optional core feature. Instantiation of the I-cache is controlled by the RV_ICACHE_ENABLE build argument. ::: ## Feature Descriptions ### Cache Flushing As described in [](memory-map.md#memory-synchronization-trigger-register-dmst), a debugger may initiate an operation that is equivalent to a `fence.i` instruction by writing a '1' to the *fence_i* field of the `dmst` register. As part of executing this operation, the I-cache is flushed (i.e., all entries in the I-cache are invalidated). ### Enabling/Disabling I-Cache As described in [](memory-map.md#region-access-control-register-mrac), each of the 16 memory regions has two control bits which are hosted in the `mrac` register. One of these control bits, *cacheable*, controls if accesses to that region may be cached. If the *cacheable* bits of all 16 regions are set to '0', the I-cache is effectively turned off. ### Diagnostic Access For firmware as well as hardware debug, direct access to the raw content of the data array, tag array, and status bits of the I-cache may be important. Instructions stored in the cache, the tag of a cache line as well as status information including a line's valid bit and a set's LRU bits can be manipulated. It is also possible to inject a parity/ECC error in the data or tag array to check error recovery. Five control registers are used to provide read/write diagnostic access to the two arrays and status bits. The `dicawics` register controls the selection of the array, way, and index of a cache line. The `dicad0/0h/1` and `dicago` registers are used to perform a read or write access to the selected array location. See sections [](cache.md#i-cache-arraywayindex-selection-register-dicawics) - [](cache.md#i-cache-array-go-register-dicago) for more detailed information. :::{note} The instructions and the tags are stored in parity/ECC-protected SRAM arrays. The status bits are stored in flops. ::: ## Use Cases The I-cache control features can be broadly divided into two categories: 1. Debug Support A few examples how diagnostic accesses ([](cache.md#diagnostic-access)) may be useful for debug: * Generating an I-cache dump (e.g., to investigate performance issues). * Injecting parity/ECC errors in the data or tag array of the I-cache. * Diagnosing stuck-at bits in the data or tag array of the I-cache. * Preloading the I-cache if a hardware bug prevents instruction fetching from memory. 2. Performance Evaluation * To evaluate the performance advantage of the I-cache, it is useful to run code with and without the cache enabled. Enabling and disabling the I-cache ([](cache.md#enablingdisabling-i-cache)) is an essential feature for this. ## Theory Of Operation ### Read a Chunk of an I-cache Cache Line The following steps must be performed to read a 64-bit chunk of instruction data and its associated 4 parity / 7 ECC bits in an I-cache cache line: 1. Write array/way/address information which location to access in the I-cache to the `dicawics` register: * *array* field: 0 (i.e., I-cache data array), * *way* field: way to be accessed (i.e., 0..1 for 2-way or 0..3 for 4-way set-associative cache), and * *index* field: index of cache line to be accessed. 2. Read the `dicago` register which causes a read access from the I-cache data array at the location selected by the dicawics register. 3. Read the `dicad0` and `dicad0h` registers to get the selected 64-bit cache line chunk (*instr* fields), and read the `dicad1` register to get the associated parity/ECC bits (*parity0/1/2/3* / *ecc* fields). ### Write a Chunk of an I-Cache Cache Line The following steps must be performed to write a 64-bit chunk of instruction data and its associated 4 parity / 7 ECC bits in an I-cache cache line: 1. Write array/way/address information which location to access in the I-cache to the `dicawics` register: * *array* field: 0 (i.e., I-cache data array), * *way* field: way to be accessed (i.e., 0..1 for 2-way or 0..3 for 4-way set-associative cache), and * *index* field: index of cache line to be accessed. 2. Write the new instruction data to the *instr* fields of the `dicad0` and `dicad0h` registers, and write the calculated correct instruction parity/ECC bits (unless error injection should be performed) to the *parity0/1/2/3* / *ecc* and fields of the dicad1 register. 3. Write a '1' to the go field of the dicago register which causes a write access to the I-cache data array copying the information stored in the `dicad0/0h/1` registers to the location selected by the `dicawics` register. ### Read or Write a Full I-Cache Cache Line The following steps must be performed to read or write instruction data and associated parity/ECC bits of a full Icache cache line: 1. Start with an index naturally aligned to the 64- or 32-byte cache line size (i.e., *index[5:3]* = '000' for 64-byte or *index[4:3]* = '00' for 32-byte). 2. Perform steps in [](cache.md#read-a-chunk-of-an-i-cache-cache-line) to read or [](cache.md#write-a-chunk-of-an-i-cache-cache-line) to write. 3. Increment the index. 4. Go back to step 2.) for a total of 8 (for 64-byte line size) or 4 (for 32-byte line size) iterations. ### Read a Tag and Status Information of an I-cache Cache Line The following steps must be performed to read the tag, tag's parity/ECC bit(s), and status information of an I-cache cache line: 1. Write array/way/address information which location to access in the I-cache to the `dicawics` register: * *array* field: 1 (i.e., I-cache tag array and status), * *way* field: way to be accessed (i.e., 0..1 for 2-way or 0..3 for 4-way set-associative cache), and * *index* field: index of cache line to be accessed. 2. Read the `dicago` register which causes a read access from the I-cache tag array and status bits at the location selected by the `dicawics` register. 3. Read the `dicad0` register to get the selected cache line's tag (*tag* field) and valid bit (*valid* field) as well as the set's LRU bits (*lru* field), and read the `dicad1` register to get the tag's parity/ECC bit(s) (*parity0* / *ecc* field). ### Write a Tag and Status Information of an I-Cache Cache Line The following steps must be performed to write the tag, tag's parity/ECC bit, and status information of an I-cache cache line: 1. Write array/way/address information which location to access in the I-cache to the `dicawics` register: * *array* field: 1 (i.e., I-cache tag array and status), * *way* field: way to be accessed (i.e., 0..1 for 2-way or 0..3 for 4-way set-associative cache), and * *index* field: index of cache line to be accessed. 2. Write the new tag, valid, and LRU information to the *tag, valid*, and *lru* fields of the `dicad0` register, and write the calculated correct tag parity/ECC bit (unless error injection should be performed) to the *parity0* / *ecc* field of the `dicad1` register. 3. Write a '1' to the *go* field of the `dicago` register which causes a write access to the I-cache tag array and status bits copying the information stored in the dicad0/1 registers to the location selected by the `dicawics` register. ## I-Cache Control/Status Registers A summary of the I-cache control/status registers in CSR address space: * [](cache.md#i-cache-arraywayindex-selection-register-dicawics) * [](cache.md#i-cache-array-data-0-register-dicad0) * [](cache.md#i-cache-array-data-0-high-register-dicad0h) * [](cache.md#i-cache-array-data-1-register-dicad1) * [](cache.md#i-cache-array-go-register-dicago) All reserved and unused bits in these control/status registers must be hardwired to '0'. Unless otherwise noted, all read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. ### I-Cache Array/Way/Index Selection Register (dicawics) The `dicawics` register is used to select a specific location in either the data array or the tag array / status of the Icache. In addition to selecting the array, the location in the array must be specified by providing the way, and index. Once selected, the `dicad0/0h/1` registers (see [](cache.md#i-cache-array-data-0-register-dicad0), [](cache.md#i-cache-array-data-0-high-register-dicad0h), and [](cache.md#i-cache-array-data-1-register-dicad1)) hold the information read from or to be written to the specified location, and the dicago register (see [](cache.md#i-cache-array-go-register-dicago)) is used to control the read/write access to the specified I-cache array. The cache line size of the I-cache is either 64 or 32 bytes. The `dicawics` register addresses a 64-bit chunk of instruction data or a cache line tag with its associated status. Each 64-bit instruction data chunk is protected either with four parity bits (each covering 16 consecutive instruction data bits) or with 7-bit ECC (covering all 64 instruction data bits). There are 8 such chunks in a 64-byte or 4 such chunks in a 32-byte cache line. Each cache line tag is protected either with a single parity bit or with 5-bit ECC. :::{note} This register is accessible in **Debug Mode only**. Attempting to access this register in machine mode raises an illegal instruction exception. ::: This register is mapped to the non-standard read-write CSR address space. :::{list-table} I-Cache Array/Way/Index Selection Register (dicawics, at CSR 0x7C8) :name: tab-cache-array-dicawics :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:25 - Reserved - R - 0 * - array - 24 - Array select: 0: I-cache data array (incl. parity/ECC bits) 1: I-cache tag array (incl. parity/ECC bits) and status (incl. valid and LRU bits) - R/W - 0 * - Reserved - 23:22 - Reserved - R - 0 * - way - 21:20 - Way select: Four-way set-associative cache: *way[21:20]* Two-way set-associative cache: *way[20]* (*way[21]* reserved, must be 0) - R/W - 0 * - Reserved - 19:17 - Reserved - R - 0 * - index [^fn-cache-1] - 16:3 - Index address bits select **Notes:** - Index bits are right-justified: - For 4-way set-associative cache, *index[16]* and other unused upper bits (for I-cache sizes smaller than 256KB) must be 0 - For 2-way set-associative cache, unused upper bits (for I-cache sizes smaller than 256KB) must be 0 - For tag array and status access: - For 64-byte cache line size, bits 5..3 are ignored by hardware - For 32-byte cache line size, bits 4..3 are ignored by hardware - This field does not have WARL behavior - R/W - 0 * - Reserved - 2:0 - Reserved - R - 0 ::: [^fn-cache-1]: VeeR EL2’s I-cache supports four- or two-way set-associativity and cache line sizes of 64 or 32 bytes. Each way is subdivided into 2 banks, and each bank is 8 bytes wide. A bank is selected by index[3], and index[2:0] address a byte of the 8-byte wide bank. ### I-Cache Array Data 0 Register (dicad0) The `dicad0` register, in combination with the `dicad0h/1` registers (see [](cache.md#i-cache-array-data-0-high-register-dicad0h) and [](cache.md#i-cache-array-data-1-register-dicad1)), is used to store information read from or to be written to the I-cache array location specified with the `dicawics` register (see [](cache.md#i-cache-arraywayindex-selection-register-dicawics)). Triggering a read or write access of the I-cache array is controlled by the `dicago` register (see [](cache.md#i-cache-array-go-register-dicago)). The layout of the dicad0 register is different for the data array and the tag array / status, as described in {numref}`tab-cache-array-dicad0` below. :::{note} During normal operation, the parity/ECC bits over the 64-bit instruction data as well as the tag are generated and checked by hardware. However, to enable error injection, the parity/ECC bits must be computed by software for I-cache data and tag array diagnostic writes. ::: :::{note} This register is accessible in **Debug Mode only**. Attempting to access this register in machine mode raises an illegal instruction exception. ::: This register is mapped to the non-standard read-write CSR address space. :::{list-table} I-Cache Array Data 0 Register (dicad0, at CSR 0x7C9) :name: tab-cache-array-dicad0 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset|** * - **I-cache data array** - - - - * - instr - 31:0 - Instruction data 31:16: instruction data bytes 3/2 (protected by *parity1* / *ecc*) 15:0: instruction data bytes 1/0 (protected by *parity0* / *ecc*) - R/W - 0 * - **I-cache tag array and status bits** - - - - * - tag - 31:11 - Tag **Note:** Tag bits are right-justified; unused higher bits (for I-cache sizes larger than 8KB) must be 0 - R/W - 0 * - Unused - 10:7 - Unused - R/W - 0 * - lru - 6:4 - Pseudo LRU bits (same bits are accessed independent of selected way): Four-way set-associative cache: - *lru[4]*: way0/1 / way2/3 selection - 0: way0/1 - 1: way2/3 - *lru[5]*: way0 / way1 selection - 0: way0 - 1: way1 - *lru[6]*: way2 / way3 selection - 0: way2 - 1: way3 Two-way set-associative cache: - *lru[4]*: way0 / way1 selection - 0: way0 - 1: way1 - *lru[6:5]*: Reserved (must be 0) - R/W - 0 * - Unused - 3:1 - Unused - R/W - 0 * - valid - 0 - Cache line valid/invalid: - 0: cache line invalid - 1: cache line valid - R/W - 0 ::: ### I-Cache Array Data 0 High Register (dicad0h) The `dicad0h` register, in combination with the `dicad0` and `dicad1` registers (see [](cache.md#i-cache-array-data-0-register-dicad0) and [](cache.md#i-cache-array-data-1-register-dicad1)), is used to store information read from or to be written to the I-cache array location specified with the `dicawics` register (see [](cache.md#i-cache-arraywayindex-selection-register-dicawics)). Triggering a read or write access of the I-cache array is controlled by the dicago register (see [](cache.md#i-cache-array-go-register-dicago)). The layout of the `dicad0h` register is described in {numref}`tab-cache-array-dicad0h` below. :::{note} During normal operation, the parity/ECC bits over the 64-bit instruction data as well as the tag are generated and checked by hardware. However, to enable error injection, the parity/ECC bits must be computed by software for I-cache data and tag array diagnostic writes. ::: :::{note} This register is accessible in **Debug Mode only**. Attempting to access this register in machine mode raises an illegal instruction exception. ::: This register is mapped to the non-standard read-write CSR address space. :::{list-table} I-Cache Array Data 0 High Register (dicad0h, at CSR 0x7CC) :name: tab-cache-array-dicad0h :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - instr - 31:0 - Instruction data 31:16: instruction data bytes 7/6 (protected by *parity3* / *ecc*) 15:0: instruction data bytes 5/4 (protected by *parity2* / *ecc*) - R/W - 0 ::: ### I-Cache Array Data 1 Register (dicad1) The `dicad1` register, in combination with the `dicad0/0h` registers (see [](cache.md#i-cache-array-data-0-register-dicad0) and [](cache.md#i-cache-array-data-0-high-register-dicad0h)), is used to store information read from or to be written to the I-cache array location specified with the `dicawics` register (see [](cache.md#i-cache-arraywayindex-selection-register-dicawics)). Triggering a read or write access of the I-cache array is controlled by the `dicago` register (see [](cache.md#i-cache-array-go-register-dicago)). The layout of the `dicad1` register is described in {numref}`tab-cache-array-dicad1` below. :::{note} During normal operation, the parity/ECC bits over the 64-bit instruction data as well as the tag are generated and checked by hardware. However, to enable error injection, the parity/ECC bits must be computed by software for I-cache data and tag array diagnostic writes. ::: :::{note} This register is accessible in **Debug Mode only**. Attempting to access this register in machine mode raises an illegal instruction exception. ::: This register is mapped to the non-standard read-write CSR address space. :::{list-table} I-Cache Array Data 1 Register (dicad1, at CSR 0x7CA). :name: tab-cache-array-dicad1 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - **Parity** - - - - * - **Instruction data** - - - - * - Reserved - 31:4 - Reserved - R - 0 * - parity3 - 3 - Even parity for I-cache data bytes 7/6 (*instr[31:16]* in `dicad0h`) - R/W - 0 * - parity2 - 2 - Even parity for I-cache data bytes 5/4 (*instr[15:0]* in `dicad0h`) - R/W - 0 * - parity1 - 1 - Even parity for I-cache data bytes 3/2 (*instr[31:16]* in `dicad0`) - R/W - 0 * - parity0 - 0 - Even parity for I-cache data bytes 1/0 (*instr[15:0]* in `dicad0`) - R/W - 0 * - **Tag** - - - - * - Reserved - 31:1 - Reserved - R - 0 * - parity0 - 0 - Even parity for I-cache tag (tag) - R/W - 0 * - **ECC** - - - - * - **Instruction data** - - - - * - Reserved - 31:7 - Reserved - R - 0 * - ecc - 6:0 - ECC for I-cache data bytes 7/6/5/4/3/2/1/0 (*instr[31:0]* in `dicad0h` and *instr[31:0]* in `dicad0`) - R/W - 0 * - **Tag** - - - - * - Reserved - 31:5 - Reserved - R - 0 * - ecc - 4:0 - ECC for I-cache tag (tag) - R/W - 0 ::: ### I-Cache Array Go Register (dicago) The `dicago` register is used to trigger a read from or write to the I-cache array location specified with the `dicawics` register (see [](cache.md#i-cache-arraywayindex-selection-register-dicawics)). Reading the `dicago` register populates the `dicad0/dicad0h/dicad1` registers (see [](cache.md#i-cache-array-data-0-register-dicad0), [](cache.md#i-cache-array-data-0-high-register-dicad0h), and [](cache.md#i-cache-array-data-1-register-dicad1)) with the information read from the I-cache array. Writing a '1' to the go field of the dicago register copies the information stored in the dicad0/dicad0h /dicad1 registers to the I-cache array. The layout of the dicago register is described in {numref}`tab-cache-array-dicago` below. :::{note} This register is accessible in **Debug Mode only**. Attempting to access this register in machine mode raises an illegal instruction exception. ::: The *go* field of the `dicago` register has W1R0 (Write 1, Read 0) behavior, as also indicated in the 'Access' column. This register is mapped to the non-standard read-write CSR address space. :::{list-table} I-Cache Array Go Register (dicago, at CSR 0x7CB) :name: tab-cache-array-dicago :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:1 - Reserved - R - 0 * - go - 0 - Read triggers an I-cache read, write-1 triggers an I-cache write - R0/W1 - 0 ::: ================================================ FILE: docs/source/clocks.md ================================================ # Clock And Reset This chapter describes clocking and reset signals used by the VeeR EL2 core complex. ## Features The VeeR EL2 core complex's clock and reset features are: * Support for independent clock ratios for four separate system bus interfaces * System bus clock ratios controlled by SoC * Single core complex clock input * System bus clock ratios controlled by enable signals * Single core complex reset signal * Ability to reset to Debug Mode * Separate Debug Module reset signal * Allows to interact with Debug Module when core complex is still in reset ## Clocking ### Regular Operation The VeeR EL2 core complex is driven by a single clock (`clk`). All input and output signals, except those listed in {numref}`tab-core-complex-async-signals`, are synchronous to `clk`. The core complex provides three master system bus interfaces (for instruction fetch, load/store data, and debug) as well as one slave (DMA) system bus interface. The SoC controls the clock ratio for each system bus interface via the clock enable signal (`*_bus_clk_en`). The clock ratios selected by the SoC may be the same or different for each system bus. {numref}`fig-data-timing-relationship` depicts the conceptual relationship of the clock (`clk`), system bus enable (`*_bus_clk_en`) used to select the clock ratio for each system bus, and the data (`*data`) of the respective system bus. :::{figure-md} fig-data-timing-relationship ![Data Timing Relationship](img/clock_timing.png) Conceptual Clock, Clock-Enable, and Data Timing Relationship ::: Note that the clock net is not explicitly buffered, as the clock tree is expected to be synthesized during place-androute. The achievable clock frequency depends on the configuration, the sizes and configuration of I-cache and I/DCCMs, and the silicon implementation technology. ### System Bus-to-Core Clock Ratios {numref}`fig-1-1-bus2core-clock-ratio` to {numref}`fig-1-8-bus2core-clock-ratio` depict the timing relationships of clock, clock-enable, and data for the supported system bus clock ratios from 1:1 (i.e. the system bus and core run at the same rate) to 1:8 (i.e. the system bus runs eight times slower than the core). :::{figure-md} fig-1-1-bus2core-clock-ratio ![1 1 Bus-to-Core Clock Ratio](img/1_1_bus2core_clock_ratio.png) 1:1 System Bus-to-Core Clock Ratio ::: :::{figure-md} fig-1-2-bus2core-clock-ratio ![1 2 Bus-to-Core Clock Ratio](img/1_2_bus2core_clock_ratio.png) 1:2 System Bus-to-Core Clock Ratio ::: :::{figure-md} fig-1-3-bus2core-clock-ratio ![1 3 Bus-to-Core Clock Ratio](img/1_3_bus2core_clock_ratio.png) 1:3 System Bus-to-Core Clock Ratio ::: :::{figure-md} fig-1-4-bus2core-clock-ratio ![1 4 Bus-to-Core Clock Ratio](img/1_4_bus2core_clock_ratio.png) 1:4 System Bus-to-Core Clock Ratio ::: :::{figure-md} fig-1-5-bus2core-clock-ratio ![1 5 Bus-to-Core Clock Ratio](img/1_5_bus2core_clock_ratio.png) 1:5 System Bus-to-Core Clock Ratio ::: :::{figure-md} fig-1-6-bus2core-clock-ratio ![1 6 Bus-to-Core Clock Ratio](img/1_6_bus2core_clock_ratio.png) 1:6 System Bus-to-Core Clock Ratio ::: :::{figure-md} fig-1-7-bus2core-clock-ratio ![1 7 Bus-to-Core Clock Ratio](img/1_7_bus2core_clock_ratio.png) 1:7 System Bus-to-Core Clock Ratio ::: :::{figure-md} fig-1-8-bus2core-clock-ratio ![1 8 Bus-to-Core Clock Ratio](img/1_8_bus2core_clock_ratio.png) 1:8 System Bus-to-Core Clock Ratio ::: ### Asynchronous Signals {numref}`tab-core-complex-async-signals` provides a list of signals which are asynchronous to the core clock (`clk`). Signals which are inputs to the core complex are synchronized to `clk` in the core complex logic. Signals which are outputs of the core complex must be synchronized outside of the core complex logic if the respective receiving clock domain is driven by a different clock than `clk`. Note that each asynchronous input passes through a two-stage synchronizer. The signal must be asserted for at least two full `clk` cycles to guarantee it is detected by the core complex logic. Shorter pulses might be dropped by the synchronizer circuit. :::{list-table} Core Complex Asynchronous Signals :name: tab-core-complex-async-signals :header-rows: 1 - * Signal * Dir * Description - * **Interrupts** * * - * extintsrc_req[pt.PIC_TOTAL_INT:1] * in * External interrupts - * soft_int * in * Standard RISC-V software interrupt - * timer_int * in * Standard RISC-V timer interrupt - * nmi_int * in * Non-Maskable Interrupt| - * **Power Management Unit (PMU) Interface** * * - * i_cpu_halt_req * in * PMU halt request to core - * i_cpu_run_req * in * PMU run request to core - * **Multi-Processor Controller (MPC) Debug Interface** * * - * mpc_debug_halt_req * in * MPC debug halt request to core - * mpc_debug_run_req * in * MPC debug run request to core - * **JTAG** * * - * jtag_tck * in * JTAG Test Clock - * jtag_tms * in * JTAG Test Mode Select (synchronous to jtag_tck) - * jtag_tdi * in * JTAG Test Data In (synchronous to jtag_tck) - * jtag_trst_n * in * JTAG Test Reset - * jtag_tdo * out * JTAG Test Data Out (synchronous to jtag_tck) ::: ## Reset The VeeR EL2 core complex provides two reset signals, the core complex reset, see [](#core-complex-reset-rst_l) and the Debug Module reset, see [](#debug-module-reset-dbg_rst_l). ### Core Complex Reset (rst_l) As shown in {numref}`fig-clock-reset-timing`, the core complex reset signal (`rst_l`) is active-low, may be asynchronously asserted, but must be synchronously deasserted to avoid any glitches. The `rst_l` input signal is not synchronized to the core clock (`clk`) inside the core complex logic. All core complex flops are reset asynchronously. :::{figure-md} fig-clock-reset-timing ![Clock Reset Timing](img/clock_reset_timing.png) Conceptual Clock and Reset Timing Relationship ::: Note that the core complex clock (`clk`) must be stable before the core complex reset (`rst_l`) is deasserted. :::{note} From a backend perspective, care should be taken during place-and-route optimization steps to adequately build buffer tree and distribution network of the `rst_l` signal. Slew (transition time) targets should be in the same range as functional signals and distribution delays should be closely matched to clock delays, to maintain reasonable latencies and skews. Further, `rst_l` specific timing checks can be performed during final signoff timing to ensure proper functionality, though they are more complex and challenging to model through static timing analysis. ::: :::{note} The core complex reset signal resets the entire VeeR EL2 core complex, except the Debug Module. ::: ### Debug Module Reset (dbg_rst_l) The Debug Module reset signal (`dbg_rst_l`) is an active-low signal which resets the VeeR EL2 core complex's Debug Module as well as the synchronizers between the JTAG interface and the core complex. The Debug Module reset signal may be connected to the power-on reset signal of the SoC. This allows an external debugger to interact with the Debug Module when the core complex reset signal (`rst_l`) is still asserted. If this layered reset functionality is not required, the `dbg_rst_l` signal may be tied to the `rst_l` signal outside the core complex. ### Debugger Initiating Reset via JTAG Interface A debugger may also initiate a reset of the core complex logic via the JTAG interface. Note that such a reset assertion is not visible to the SoC. Resetting the core complex while the core is accessing any SoC memory locations may result in unpredictable behavior. Recovery may require an assertion of the SoC master reset. ### Core Complex Reset to Debug Mode The RISC-V Debug specification [[3]](intro.md#ref-3) states a requirement that the debugger must be able to be in control from the first executed instruction of a program after a reset. The `dmcontrol` register, see [](debugging.md#debug-module-control-register-dmcontrol), of the Debug Module controls the core-complex-internal ndmreset (non-debug module reset) signal. This signal resets the core complex (except for the Debug Module and Debug Transport Module). The following sequence is used to reset the core and execute the first instruction in Debug Mode (i.e., db-halt state): 1. Take Debug Module out of reset * Set *dmactive* bit of `dmcontrol` register (`dmcontrol` = 0x0000_0001) 2. Reset core complex * Set *ndmreset* bit of `dmcontrol` register (`dmcontrol` = 0x0000_0003) 3. While in reset, assert halt request with ndmreset still asserted * Set *haltreq* bit of `dmcontrol` register (`dmcontrol` = 0x8000_0003) 4. Take core complex out of reset with halt request still asserted * Clear *ndmreset* bit of `dmcontrol` register (`dmcontrol` = 0x8000_0001) ================================================ FILE: docs/source/complex-ports.md ================================================ # Complex Port List {numref}`tab-core-complex-signals` lists the core complex signals. Not all signals are present in a given instantiation. For example, a core complex can only have one bus interface type (AXI4 or AHB-Lite). Signals which are asynchronous to the core complex clock (`clk`) are marked with "(async)" in the 'Description' column. :::{list-table} Core Complex Signals :name: tab-core-complex-signals * - **Signal** - **Dir** - **Description** * - **Clock and Clock Enables** - - * - clk - in - Core complex clock * - ifu_bus_clk_en - in - IFU master system bus clock enable * - lsu_bus_clk_en - in - LSU master system bus clock enable * - dbg_bus_clk_en - in - Debug master system bus clock enable * - dma_bus_clk_en - in - DMA slave system bus clock enable * - **Reset** - - * - rst_l - in - Core complex reset (excl. Debug Module) * - rst_vec[31:1] - in - Core reset vector * - dbg_rst_l - in - Debug Module reset (incl. JTAG synchronizers) * - **Interrupts** - - * - nmi_int - in - Non-Maskable Interrupt (async) * - nmi_vec[31:1] - in - Non-Maskable Interrupt vector * - soft_int - in - Standard RISC-V software interrupt (async) * - timer_int - in - Standard RISC-V timer interrupt (async) * - extintsrc_req[pt.PIC_TOTAL_INT:1] - in - External interrupts (async) * - **Core ID** - - * - core_id[31:4] - in - Core ID (mapped to `mhartid[31:4]`) * - **System Bus Interfaces** - - * - ***AXI4*** - - * - ***Instruction Fetch Unit Master AXI4*** [^fn-complex-ports-1] - - * - *Write address channel signals* - - * - ifu_axi_awvalid - out - Write address valid (hardwired to 0) * - ifu_axi_awready - in - Write address ready * - ifu_axi_awid[pt.IFU_BUS_TAG-1:0] - out - Write address ID * - ifu_axi_awaddr[31:0] - out - Write address * - ifu_axi_awlen[7:0] - out - Burst length * - ifu_axi_awsize[2:0] - out - Burst size * - ifu_axi_awburst[1:0] - out - Burst type * - ifu_axi_awlock - out - Lock type * - ifu_axi_awcache[3:0] - out - Memory type * - ifu_axi_awprot[2:0] - out - Protection type * - ifu_axi_awqos[3:0] - out - Quality of Service (QoS) * - ifu_axi_awregion[3:0] - out - Region identifier * - *Write data channel signals* - - * - ifu_axi_wvalid - out - Write valid (hardwired to 0) * - ifu_axi_wready - in - Write ready * - ifu_axi_wdata[63:0] - out - Write data * - ifu_axi_wstrb[7:0] - out - Write strobes * - ifu_axi_wlast - out - Write last * - *Write response channel signals* - - * - ifu_axi_bvalid - in - Write response valid * - ifu_axi_bready - out - Write response ready (hardwired to 0) * - ifu_axi_bid[pt.IFU_BUS_TAG-1:0] - in - Response ID tag * - ifu_axi_bresp[1:0] - in - Write response * - *Read address channel signals* - - * - ifu_axi_arvalid - out - Read address valid * - ifu_axi_arready - in - Read address ready * - ifu_axi_arid[pt.IFU_BUS_TAG-1:0] - out - Read address ID * - ifu_axi_araddr[31:0] - out - Read address * - ifu_axi_arlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - ifu_axi_arsize[2:0] - out - Burst size (hardwired to 0b011) * - ifu_axi_arburst[1:0] - out - Burst type (hardwired to 0b01) * - ifu_axi_arlock - out - Lock type (hardwired to 0) * - ifu_axi_arcache[3:0] - out - Memory type (hardwired to 0b1111) * - ifu_axi_arprot[2:0] - out - Protection type (hardwired to 0b100) * - ifu_axi_arqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - ifu_axi_arregion[3:0] - out - Region identifier * - *Read data channel signals* - - * - ifu_axi_rvalid - in - Read valid * - ifu_axi_rready - out - Read ready * - ifu_axi_rid[pt.IFU_BUS_TAG-1:0] - in - Read ID tag * - ifu_axi_rdata[63:0] - in - Read data * - ifu_axi_rresp[1:0] - in - Read response * - ifu_axi_rlast - in - Read last * - ***Load/Store Unit Master AXI4*** - - * - *Write address channel signals* - - * - lsu_axi_awvalid - out - Write address valid * - lsu_axi_awready - in - Write address ready * - lsu_axi_awid[pt.LSU_BUS_TAG-1:0] - out - Write address ID * - lsu_axi_awaddr[31:0] - out - Write address * - lsu_axi_awlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - lsu_axi_awsize[2:0] - out - Burst size * - lsu_axi_awburst[1:0] - out - Burst type (hardwired to 0b01) * - lsu_axi_awlock - out - Lock type (hardwired to 0) * - lsu_axi_awcache[3:0] - out - Memory type * - lsu_axi_awprot[2:0] - out - Protection type (hardwired to 0b000) * - lsu_axi_awqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - lsu_axi_awregion[3:0] - out - Region identifier * - *Write data channel signals* - - * - lsu_axi_wvalid - out - Write valid * - lsu_axi_wready - in - Write ready * - lsu_axi_wdata[63:0] - out - Write data * - lsu_axi_wstrb[7:0] - out - Write strobes * - lsu_axi_wlast - out - Write last * - *Write response channel signals* - - * - lsu_axi_bvalid - in - Write response valid * - lsu_axi_bready - out - Write response ready * - lsu_axi_bid[pt.LSU_BUS_TAG-1:0] - in - Response ID tag * - lsu_axi_bresp[1:0] - in - Write response * - *Read address channel signals* - - * - lsu_axi_arvalid - out - Read address valid * - lsu_axi_arready - in - Read address ready * - lsu_axi_arid[pt.LSU_BUS_TAG-1:0] - out - Read address ID * - lsu_axi_araddr[31:0] - out - Read address * - lsu_axi_arlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - lsu_axi_arsize[2:0] - out - Burst size * - lsu_axi_arburst[1:0] - out - Burst type (hardwired to 0b01) * - lsu_axi_arlock - out - Lock type (hardwired to 0) * - lsu_axi_arcache[3:0] - out - Memory type * - lsu_axi_arprot[2:0] - out - Protection type (hardwired to 0b000) * - lsu_axi_arqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - lsu_axi_arregion[3:0] - out - Region identifier * - *Read data channel signals* - - * - lsu_axi_rvalid - in - Read valid * - lsu_axi_rready - out - Read ready * - lsu_axi_rid[pt.LSU_BUS_TAG-1:0] - in - Read ID tag * - lsu_axi_rdata[63:0] - in - Read data * - lsu_axi_rresp[1:0] - in - Read response * - lsu_axi_rlast - in - Read last * - ***System Bus (Debug) Master AXI4*** - - * - *Write address channel signals* - - * - sb_axi_awvalid - out - Write address valid * - sb_axi_awready - in - Write address ready * - sb_axi_awid[pt.SB_BUS_TAG-1:0] - out - Write address ID (hardwired to 0) * - sb_axi_awaddr[31:0] - out - Write address * - sb_axi_awlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - sb_axi_awsize[2:0] - out - Burst size * - sb_axi_awburst[1:0] - out - Burst type (hardwired to 0b01) * - sb_axi_awlock - out - Lock type (hardwired to 0) * - sb_axi_awcache[3:0] - out - Memory type (hardwired to 0b1111) * - sb_axi_awprot[2:0] - out - Protection type (hardwired to 0b000) * - sb_axi_awqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - sb_axi_awregion[3:0] - out - Region identifier * - *Write data channel signals* - - * - sb_axi_wvalid - out - Write valid * - sb_axi_wready - in - Write ready * - sb_axi_wdata[63:0] - out - Write data * - sb_axi_wstrb[7:0] - out - Write strobes * - sb_axi_wlast - out - Write last * - *Write response channel signals* - - * - sb_axi_bvalid - in - Write response valid * - sb_axi_bready - out - Write response ready * - sb_axi_bid[pt.SB_BUS_TAG-1:0] - in - Response ID tag * - sb_axi_bresp[1:0] - in - Write response * - *Read address channel signals* - - * - sb_axi_arvalid - out - Read address valid * - sb_axi_arready - in - Read address ready * - sb_axi_arid[pt.SB_BUS_TAG-1:0] - out - Read address ID (hardwired to 0) * - sb_axi_araddr[31:0] - out - Read address * - sb_axi_arlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - sb_axi_arsize[2:0] - out - Burst size * - sb_axi_arburst[1:0] - out - Burst type (hardwired to 0b01) * - sb_axi_arlock - out - Lock type (hardwired to 0) * - sb_axi_arcache[3:0] - out - Memory type (hardwired to 0b0000) * - sb_axi_arprot[2:0] - out - Protection type (hardwired to 0b000) * - sb_axi_arqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - sb_axi_arregion[3:0] - out - Region identifier * - *Read data channel signals* - - * - sb_axi_rvalid - in - Read valid * - sb_axi_rready - out - Read ready * - sb_axi_rid[pt.SB_BUS_TAG-1:0] - in - Read ID tag * - sb_axi_rdata[63:0] - in - Read data * - sb_axi_rresp[1:0] - in - Read response * - sb_axi_rlast - in - Read last * - ***DMA Slave AXI4*** - - * - *Write address channel signals* - - * - dma_axi_awvalid - in - Write address valid * - dma_axi_awready - out - Write address ready * - dma_axi_awid[pt.DMA_BUS_TAG-1:0] - in - Write address ID * - dma_axi_awaddr[31:0] - in - Write address * - dma_axi_awlen[7:0] - in - Burst length * - dma_axi_awsize[2:0] - in - Burst size * - dma_axi_awburst[1:0] - in - Burst type * - dma_axi_awprot[2:0] - in - Protection type * - *Write data channel signals* - - * - dma_axi_wvalid - in - Write valid * - dma_axi_wready - out - Write ready * - dma_axi_wdata[63:0] - in - Write data * - dma_axi_wstrb[7:0] - in - Write strobes * - dma_axi_wlast - in - Write last * - *Write response channel signals* - - * - dma_axi_bvalid - out - Write response valid * - dma_axi_bready - in - Write response ready * - dma_axi_bid[pt.DMA_BUS_TAG-1:0] - out - Response ID tag * - dma_axi_bresp[1:0] - out - Write response * - *Read address channel signals* - - * - dma_axi_arvalid - in - Read address valid * - dma_axi_arready - out - Read address ready * - dma_axi_arid[pt.DMA_BUS_TAG-1:0] - in - Read address ID * - dma_axi_araddr[31:0] - in - Read address * - dma_axi_arlen[7:0] - in - Burst length * - dma_axi_arsize[2:0] - in - Burst size * - dma_axi_arburst[1:0] - in - Burst type * - dma_axi_arprot[2:0] - in - Protection type * - *Read data channel signals* - - * - dma_axi_rvalid - out - Read valid * - dma_axi_rready - in - Read ready * - dma_axi_rid[pt.DMA_BUS_TAG-1:0] - out - Read ID tag * - dma_axi_rdata[63:0] - out - Read data * - dma_axi_rresp[1:0] - out - Read response * - dma_axi_rlast - out - Read last * - ***AHB-Lite*** - - * - ***Instruction Fetch Unit Master AHB-Lite*** - - * - *Master signals* - - * - haddr[31:0] - out - System address * - hburst[2:0] - out - Burst type (hardwired to 0b000) * - hmastlock - out - Locked transfer (hardwired to 0) * - hprot[3:0] - out - Protection control * - hsize[2:0] - out - Transfer size * - htrans[1:0] - out - Transfer type * - hwrite - out - Write transfer * - *Slave signals* - - * - hrdata[63:0] - in - Read data * - hready - in - Transfer finished * - hresp - in - Slave transfer response * - ***Load/Store Unit Master AHB-Lite*** - - * - *Master signals* - - * - lsu_haddr[31:0] - out - System address * - lsu_hburst[2:0] - out - Burst type (hardwired to 0b000) * - lsu_hmastlock - out - Locked transfer (hardwired to 0) * - lsu_hprot[3:0] - out - Protection control * - lsu_hsize[2:0] - out - Transfer size * - lsu_htrans[1:0] - out - Transfer type * - lsu_hwdata[63:0] - out - Write data * - lsu_hwrite - out - Write transfer * - *Slave signals* - - * - lsu_hrdata[63:0] - in - Read data * - lsu_hready - in - Transfer finished * - lsu_hresp - in - Slave transfer response * - ***System Bus (Debug) Master AHB-Lite*** - - * - *Master signals* - - * - sb_haddr[31:0] - out - System address * - sb_hburst[2:0] - out - Burst type (hardwired to 0b000) * - sb_hmastlock - out - Locked transfer (hardwired to 0) * - sb_hprot[3:0] - out - Protection control * - sb_hsize[2:0] - out - Transfer size * - sb_htrans[1:0] - out - Transfer type * - sb_hwdata[63:0] - out - Write data * - sb_hwrite - out - Write transfer * - *Slave signals* - - * - sb_hrdata[63:0] - in - Read data * - sb_hready - in - Transfer finished * - sb_hresp - in - Slave transfer response * - ***DMA Slave AHB-Lite*** - - * - *Slave signals* - - * - dma_haddr[31:0] - in - System address * - dma_hburst[2:0] - in - Burst type * - dma_hmastlock - in - Locked transfer * - dma_hprot[3:0] - in - Protection control * - dma_hsize[2:0] - in - Transfer size * - dma_htrans[1:0] - in - Transfer type * - dma_hwdata[63:0] - in - Write data * - dma_hwrite - in - Write transfer * - dma_hsel - in - Slave select * - dma_hreadyin - in - Transfer finished in * - *Master signals* - - * - dma_hrdata[63:0] - out - Read data * - dma_hreadyout - out - Transfer finished * - dma_hresp - out - Slave transfer response * - **Power Management Unit (PMU) Interface** - - * - i_cpu_halt_req - in - PMU halt request to core (async) * - o_cpu_halt_ack - out - Core acknowledgement for PMU halt request * - o_cpu_halt_status - out - Core halted indication * - i_cpu_run_req - in - PMU run request to core (async) * - o_cpu_run_ack - out - Core acknowledgement for PMU run request * - **Multi-Processor Controller (MPC) Debug Interface** - - * - mpc_debug_halt_req - in - MPC debug halt request to core (async) * - mpc_debug_halt_ack - out - Core acknowledgement for MPC debug halt request * - mpc_debug_run_req - in - MPC debug run request to core (async) * - mpc_debug_run_ack - out - Core acknowledgement for MPC debug run request * - mpc_reset_run_req - in - Core start state control out of reset * - o_debug_mode_status - out - Core in Debug Mode indication * - debug_brkpt_status - out - Hardware/software breakpoint indication * - **Performance Counter Activity** - - * - dec_tlu_perfcnt0 - out - Performance counter 0 incrementing * - dec_tlu_perfcnt1 - out - Performance counter 1 incrementing * - dec_tlu_perfcnt2 - out - Performance counter 2 incrementing * - dec_tlu_perfcnt3 - out - Performance counter 3 incrementing * - **Trace Port** [^fn-complex-ports-2] - - * - trace_rv_i_insn_ip[31:0] - out - Instruction opcode * - trace_rv_i_address_ip[31:0] - out - Instruction address * - trace_rv_i_valid_ip - out - Instruction trace valid * - trace_rv_i_exception_ip - out - Exception * - trace_rv_i_ecause_ip[4:0] - out - Exception cause * - trace_rv_i_interrupt_ip - out - Interrupt exception * - trace_rv_i_tval_ip[31:0] - out - Exception trap value * - **Debug JTAG Port** - - * - jtag_tck - in - JTAG Test Clock (async) * - jtag_tms - in - JTAG Test Mode Select (async, sync to jtag_tck) * - jtag_tdi - in - JTAG Test Data In (async, sync to jtag_tck) * - jtag_trst_n - in - JTAG Test Reset (async) * - jtag_tdo - out - JTAG Test Data Out (async, sync to jtag_tck) * - jtag_id[31:1] - in - JTAG IDCODE register value (bit 0 tied internally to 1) * - **Testing** - - * - scan_mode - in - May be used to enable logic scan test, if implemented (must be ‘0’ for normal core operation) * - mbist_mode - in - May be used to enable MBIST for core-internal memories, if implemented (should be tied to ‘0’ if not used) ::: [^fn-complex-ports-1]: The IFU issues only read, but no write transactions. However, the IFU write address, data, and response channels are present, but the valid/ready signals are tied off to disable those channels. [^fn-complex-ports-2]: The core provides trace information for a maximum of one instruction and one interrupt/exception per clock cycle. Note that the only information provided for interrupts/exceptions is the cause, the interrupt/exception flag, and the trap value. The core’s trace port busses are minimally sized, but wide enough to deliver all trace information the core may produce in one clock cycle. Not provided signals for the upper bits of the interface related to the interrupt slot might have to be tied off in the SoC. ================================================ FILE: docs/source/conf.py ================================================ from datetime import datetime from antmicro_sphinx_utils.defaults import ( extensions as default_extensions, myst_enable_extensions as default_myst_enable_extensions, myst_fence_as_directive as default_myst_fence_as_directive, antmicro_html, ) # General information about the project. project = u'RISC-V VeeR EL2 Programmer\'s Reference Manual' basic_filename = u'riscv-veer-el2-prm' authors = u'CHIPS Alliance The Linux Foundation®' copyright = f'{datetime.now().year} {authors}' # The short X.Y version. version = '' # The full version, including alpha/beta/rc tags. release = '' # This is temporary before the clash between myst-parser and immaterial is # fixed sphinx_immaterial_override_builtin_admonitions = False numfig = True # If you need to add extensions just add to those lists extensions = default_extensions myst_enable_extensions = default_myst_enable_extensions myst_fence_as_directive = default_myst_fence_as_directive myst_substitutions = { "project": project } myst_heading_anchors = 4 today_fmt = '%Y-%m-%d' todo_include_todos=False # -- Options for HTML output --------------------------------------------------- html_theme = 'sphinx_immaterial' html_last_updated_fmt = today_fmt html_show_sphinx = False ( html_logo, html_theme_options, html_context ) = antmicro_html() html_theme_options["palette"][0].update({ "scheme": "slate", "primary": "teal", "accent": "white", }) def setup(app): app.add_css_file('main.css') ================================================ FILE: docs/source/core-control.md ================================================ # Low-Level Core Control This chapter describes some low-level core control registers. ## Control/Status Registers A summary of platform-specific control/status registers in CSR space: * Feature Disable Control Register (mfdc), see [](core-control.md#feature-disable-control-register-mfdc) * Clock Gating Control Register (mcgc), see [](core-control.md#clock-gating-control-register-mcgc) All reserved and unused bits in these control/status registers must be hardwired to '0'. Unless otherwise noted, all read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. ### Feature Disable Control Register (mfdc) The `mfdc` register hosts low-level core control bits to disable specific features. This may be useful in case a feature intended to increase core performance should prove to have problems. :::{note} `fence.i` instructions are required before and after writes to the `mfdc` register. ::: :::{note} The default state of the controllable features is 'enabled'. Firmware may turn off a feature if needed. ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} Feature Disable Control Register (mfdc, at CSR 0x7F9). Field Bits Description :name: tab-feature-disable-cr :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:19 - Reserved - R - 0 * - dqc - 18:16 - DMA QoS control, see [](memory-map.md#quality-of-service) - R/W - 7 * - Reserved - 15:13 - Reserved - R - 0 * - td - 12 - Trace disable: - 0: enable trace - 1: disable trace - R/W - 0 * - elfd - 11 - External load-to-load forwarding disable: - 0: enable external load-to-load forwarding - 1: disable external load-to-load forwarding - R/W - 0 * - Reserved - 10:9 - Reserved - R - 0 * - cecd - 8 - Core ECC check disable: - 0: ICCM/DCCM ECC checking enabled - 1: ICCM/DCCM ECC checking disabled - R/W - 0 * - Reserved - 7 - Reserved - R - 0 * - sepd - 6 - Side effect pipelining disable: - 0: side effect loads/stores are pipelined - 1: side effect loads/stores block all subsequent bus transactions until load/store response with default value received. **Note**: Reset value depends on selected bus core build argument - R/W - 0 (*AHB-Lite*) / 1 (*AXI4*) * - Reserved - 5:4 - Reserved - R - 0 * - bpd - 3 - Branch prediction disable: - 0: enable branch prediction and return address stack - 1: disable branch prediction and return address stack - R/W - 0 * - wbcd - 2 - Write Buffer (WB) coalescing disable: - 0: enable Write Buffer coalescing - 1: disable Write Buffer coalescing - R/W - 0 * - Reserved - 1 - Reserved - R - 0 * - pd - 0 - Pipelining disable: - 0: pipelined execution - 1: single instruction execution - R/W - 0 ::: ### Clock Gating Control Register (mcgc) The `mcgc` register hosts low-level core control bits to override clock gating for specific units. This may be useful in case a unit intended to be clock gated should prove to have problems when in lower power mode. :::{note} Except for PIC I/O, the default state of the clock gating overrides is 'disabled'. Firmware may turn off clock gating (i.e., set the clock gating override bit) for a specific unit if needed. ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} Clock Gating Control Register (mcgc, at CSR 0x7F8). Field Bits Description :name: tab-clock-gating-cr :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:10 - Reserved - R - 0 * - picio - 9 - PIC I/O clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 1 * - misc - 8 - Miscellaneous clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 * - dec - 7 - DEC clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 * - exu - 6 - EXU clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 * - ifu - 5 - IFU clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 * - lsu - 4 - LSU clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 * - bus - 3 - Bus clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 * - pic - 2 - PIC clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 * - dccm - 1 - DCCM clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 * - iccm - 0 - ICCM clock gating override: - 0: enable clock gating - 1: clock gating override - R/W - 0 ::: ================================================ FILE: docs/source/csrs.md ================================================ # CSR Address Map ## Standard RISC-V CSRs {numref}`tab-veer-el2-core-specific-std-rv-machine-information-csrs` lists the VeeR EL2 core-specific standard RISC-V Machine Information CSRs. :::{list-table} VeeR EL2 Core-Specific Standard RISC-V Machine Information CSRs :name: tab-veer-el2-core-specific-std-rv-machine-information-csrs * - **Number** - **Privilege** - **Name** - **Description** - **Value** * - 0x301 - MRW - misa - ISA and extensions **Note**: writes ignored - 0x4000_1104 * - 0xF11 - MRO - mvendorid - Vendor ID - 0x0000_0045 * - 0xF12 - MRO - marchid - Architecture ID - 0x0000_0010 * - 0xF13 - MRO - mimpid - Implementation ID - 0x0000_0004 * - 0xF14 - MRO - mhartid - Hardware thread ID - see [](adaptations.md#machine-hardware-thread-id-register-mhartid) ::: {numref}`tab-veer-el2-std-risc-v-csr-address-map` lists the VeeR EL2 standard RISC-V CSR address map. :::{list-table} VeeR EL2 Standard RISC-V CSR Address Map :name: tab-veer-el2-std-risc-v-csr-address-map * - **Number** - **Privilege** - **Name** - **Description** - **Section** * - 0x300 - MRW - mstatus - Machine status - \- * - 0x304 - MRW - mie - Machine interrupt enable - [](adaptations.md#machine-interrupt-enable-mie-and-machine-interrupt-pending-mip-registers) * - 0x305 - MRW - mtvec - Machine trap-handler base address - \- * - 0x320 - MRW - mcountinhibit - Machine counter-inhibit register - [](performance.md#standard-risc-v-registers) * - 0x323 - MRW - mhpmevent3 - Machine performance-monitoring event selector 3 - [](performance.md#standard-risc-v-registers) * - 0x324 - MRW - mhpmevent4 - Machine performance-monitoring event selector 4 - [](performance.md#standard-risc-v-registers) * - 0x325 - MRW - mhpmevent5 - Machine performance-monitoring event selector 5 - [](performance.md#standard-risc-v-registers) * - 0x326 - MRW - mhpmevent6 - Machine performance-monitoring event selector 6 - [](performance.md#standard-risc-v-registers) * - 0x340 - MRW - mscratch - Scratch register for machine trap handlers - \- * - 0x341 - MRW - mepc - Machine exception program counter - \- * - 0x342 - MRW - mcause - Machine trap cause - [](adaptations.md#machine-cause-register-mcause) * - 0x343 - MRW - mtval - Machine bad address or instruction - \- * - 0x344 - MRW - mip - Machine interrupt pending - [](adaptations.md#machine-interrupt-enable-mie-and-machine-interrupt-pending-mip-registers) * - 0x7A0 - MRW - tselect - Debug/Trace trigger register select - [](debugging.md#trigger-select-register-tselect) * - 0x7A1 - MRW - tdata1 - First Debug/Trace trigger data - [](debugging.md#trigger-data-1-register-tdata1) * - 0x7A1 - MRW - mcontrol - Match control - [](debugging.md#match-control-register-mcontrol) * - 0x7A2 - MRW - tdata2 - Second Debug/Trace trigger data - [](debugging.md#trigger-data-2-register-tdata2) * - 0x7B0 - DRW - dcsr - Debug control and status register - [](debugging.md#debug-control-and-status-register-dcsr) * - 0x7B1 - DRW - dpc - Debug PC - [](debugging.md#debug-pc-register-dpc) * - 0xB00 - MRW - mcycle - Machine cycle counter - [](performance.md#standard-risc-v-registers) * - 0xB02 - MRW - minstret - Machine instructions-retired counter - [](performance.md#standard-risc-v-registers) * - 0xB03 - MRW - mhpmcounter3 - Machine performance-monitoring counter 3 - [](performance.md#standard-risc-v-registers) * - 0xB04 - MRW - mhpmcounter4 - Machine performance-monitoring counter 4 - [](performance.md#standard-risc-v-registers) * - 0xB05 - MRW - mhpmcounter5 - Machine performance-monitoring counter 5 - [](performance.md#standard-risc-v-registers) * - 0xB06 - MRW - mhpmcounter6 - Machine performance-monitoring counter 6 - [](performance.md#standard-risc-v-registers) * - 0xB80 - MRW - mcycleh - Upper 32 bits of mcycle, RV32I only - [](performance.md#standard-risc-v-registers) * - 0xB82 - MRW - minstreth - Upper 32 bits of minstret, RV32I only - [](performance.md#standard-risc-v-registers) * - 0xB83 - MRW - mhpmcounter3h - Upper 32 bits of mhpmcounter3, RV32I only - [](performance.md#standard-risc-v-registers) * - 0xB84 - MRW - mhpmcounter4h - Upper 32 bits of mhpmcounter4, RV32I only - [](performance.md#standard-risc-v-registers) * - 0xB85 - MRW - mhpmcounter5h - Upper 32 bits of mhpmcounter5, RV32I only - [](performance.md#standard-risc-v-registers) * - 0xB86 - MRW - mhpmcounter6h - Upper 32 bits of mhpmcounter6, RV32I only - [](performance.md#standard-risc-v-registers) ::: ## Non-Standard RISC-V CSRs {numref}`tab-veer-el2-non-std-risc-v-csr-address-map` summarizes the VeeR EL2 non-standard RISC-V CSR address map. :::{list-table} VeeR EL2 Non-Standard RISC-V CSR Address Map :name: tab-veer-el2-non-std-risc-v-csr-address-map * - **Number** - **Privilege** - **Name** - **Description** - **Section** * - 0x7C0 - MRW - mrac - Region access control - [](memory-map.md#region-access-control-register-mrac) * - 0x7C2 - MRW - mcpc - Core pause control - [](power.md#core-pause-control-register-mcpc) * - 0x7C4 - DRW - dmst - Memory synchronization trigger (Debug Mode only) - [](memory-map.md#memory-synchronization-trigger-register-dmst) * - 0x7C6 - MRW - mpmc - Power management control - [](power.md#power-management-control-register-mpmc) * - 0x7C8 - DRW - dicawics - I-cache array/way/index selection (Debug Mode only) - [](cache.md#i-cache-arraywayindex-selection-register-dicawics) * - 0x7C9 - DRW - dicad0 - I-cache array data 0 (Debug Mode only) - [](cache.md#i-cache-array-data-0-register-dicad0) * - 0x7CA - DRW - dicad1 - I-cache array data 1 (Debug Mode only) - [](cache.md#i-cache-array-data-1-register-dicad1) * - 0x7CB - DRW - dicago - I-cache array go (Debug Mode only) - [](cache.md#i-cache-array-go-register-dicago) * - 0x7CC - DRW - dicad0h - I-cache array data 0 high (Debug Mode only) - [](cache.md#i-cache-array-data-0-high-register-dicad0h) * - 0x7CE - MRW - mfdht - Force debug halt threshold - [](power.md#forced-debug-halt-threshold-register-mfdht) * - 0x7CF - MRW - mfdhs - Force debug halt status - [](power.md#forced-debug-halt-status-register-mfdhs) * - 0x7D2 - MRW - mitcnt0 - Internal timer counter 0 - [](timers.md#internal-timer-counter-0--1-register-mitcnt01) * - 0x7D3 - MRW - mitb0 - Internal timer bound 0 - [](timers.md#internal-timer-bound-0--1-register-mitb01) * - 0x7D4 - MRW - mitctl0 - Internal timer control 0 - [](timers.md#internal-timer-control-0--1-register-mitctl01) * - 0x7D5 - MRW - mitcnt1 - Internal timer counter 1 - [](timers.md#internal-timer-counter-0--1-register-mitcnt01) * - 0x7D6 - MRW - mitb1 - Internal timer bound 1 - [](timers.md#internal-timer-bound-0--1-register-mitb01) * - 0x7D7 - MRW - mitctl1 - Internal timer control 1 - [](timers.md#internal-timer-control-0--1-register-mitctl01) * - 0x7F0 - MRW - micect - I-cache error counter/threshold - [](error-protection.md#i-cache-error-counterthreshold-register-micect) * - 0x7F1 - MRW - miccmect - ICCM correctable error counter/threshold - [](error-protection.md#iccm-correctable-error-counterthreshold-register-miccmect) * - 0x7F2 - MRW - mdccmect - DCCM correctable error counter/threshold - [](error-protection.md#dccm-correctable-error-counterthreshold-register-mdccmect) * - 0x7F8 - MRW - mcgc - Clock gating control - [](core-control.md#clock-gating-control-register-mcgc) * - 0x7F9 - MRW - mfdc - Feature disable control - [](core-control.md#feature-disable-control-register-mfdc) * - 0x7FF - MRW - mscause - Machine secondary cause - [](memory-map.md#machine-secondary-cause-register-mscause) * - 0xBC0 - MRW - mdeau - D-Bus error address unlock - [](memory-map.md#d-bus-error-address-unlock-register-mdeau) * - 0xBC8 - MRW - meivt - External interrupt vector table - [](interrupts.md#external-interrupt-vector-table-register-meivt) * - 0xBC9 - MRW - meipt - External interrupt priority threshold - [](interrupts.md#external-interrupt-priority-threshold-register-meipt) * - 0xBCA - MRW - meicpct - External interrupt claim ID / priority level capture trigger - [](interrupts.md#external-interrupt-claim-id--priority-level-capture-trigger-register-meicpct) * - 0xBCB - MRW - meicidpl - External interrupt claim ID's priority level - [](interrupts.md#external-interrupt-claim-ids-priority-level-register-meicidpl) * - 0xBCC - MRW - meicurpl - External interrupt current priority level - [](interrupts.md#external-interrupt-current-priority-level-register-meicurpl) * - 0xFC0 - MRO - mdseac - D-bus first error address capture - [](memory-map.md#d-bus-first-error-address-capture-register-mdseac) * - 0xFC8 - MRO - meihap - External interrupt handler address pointer - [](interrupts.md#external-interrupt-handler-address-pointer-register-meihap) ::: ================================================ FILE: docs/source/debugging.md ================================================ # Debug Support The VeeR EL2 core conforms to the "RISC-V Debug Specification 0.13.2, with JTAG DTM" document [[3]](intro.md#ref-3). This chapter provides a description of the implemented debug-related control and status register definitions. For a RISC-V debug overview and detailed feature descriptions, refer to corresponding sections in [[3]](intro.md#ref-3). ## Control/Status Registers The RISC-V Debug architecture defines three separate address spaces: JTAG, Debug Module Interface, and RISC-V CSR. The registers associated with these three address spaces are described in the following sections: * [](debugging.md#controlstatus-registers-in-jtag-address-space) * [](debugging.md#controlstatus-registers-in-debug-module-interface-address-space) * [](debugging.md#controlstatus-registers-in-risc-v-csr-address-space) ### Control/Status Registers in JTAG Address Space {numref}`tab-registers-jtag` summarizes the control/status registers in the JTAG Debug Transport Module address space. Addresses shown below are in the 5-bit JTAG address space. A control/status register is addressed by setting the 5bit JTAG IR register. :::{note} The core complex clock (`clk`) frequency must be at least twice the JTAG clock (`jtag_tck`) frequency for the JTAG data to pass correctly through the clock domain crossing synchronizers. ::: :::{list-table} Registers in JTAG Debug Transport Module Address Space :name: tab-registers-jtag :header-rows: 1 * - **JTAG DTM Address** - **Name** - **Description** - **Section** * - 0x01 - IDCODE - TAG IDCODE - [](debugging.md#idcode-register-idcode) * - 0x10 - dtmcs - DTM control and status - [](debugging.md#dtm-control-and-status-register-dtmcs) * - 0x11 - dmi - Debug module interface access - [](debugging.md#debug-module-interface-access-register-dmi) * - 0x1F - BYPASS - JTAG BYPASS - [](debugging.md#bypass-register-bypass) ::: #### IDCODE Register (IDCODE) The `IDCODE` register is a standard JTAG register. It is selected in the JTAG TAP controller's IR register when the TAP state machine is reset. The `IDCODE` register's definition is exactly as defined in IEEE Std 1149.1-2013. This register is read-only. This register is mapped to the 5-bit JTAG address space. :::{list-table} IDCODE Register (IDCODE, at JTAG 0x01) :name: tab-idcode-registers :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - version - 31:28 - Identifies release version of this part - R - `jtag_id[31:28]` value (see [](complex-ports.md)) * - partnum - 27:12 - Identifies designer's part number of this part - R - `jtag_id[27:12]` value (see [](complex-ports.md)) * - manufid - 11:1 - Identifies designer/manufacturer of this part - R - `jtag_id[11:1]` value (see [](complex-ports.md)) * - 1 - 0 - Must be '1' - R - 1 ::: #### DTM Control and Status Register (dtmcs) The `dtmcs` register controls and provides status of the Debug Transport Module (DTM). This register is mapped to the 5-bit JTAG address space. :::{list-table} DTM Control and Status Register (dtmcs, at JTAG 0x10) :name: tab-dtmcs :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:18 - Reserved - R - 0 * - dmihardreset - 17 - Not implemented **Note**: Hard reset of DTM not required in VeeR EL2 because DMI accesses always succeed. Writes to this bit ignored. - R - 0 * - dmireset - 16 - Not implemented **Note**: Reset of DTM’s error state not required in VeeR EL2 because DMI accesses always succeed. Writes to this bit ignored. - R - 0 * - Reserved - 15 - Reserved - R - 0 * - idle - 14:12 - Hint to debugger of minimum number of cycles debugger should spend in Run-Test/Idle after every DMI scan to avoid a ‘busy’ return code (*dmistat* of 3). Debugger must still check *dmistat* when necessary: - 0: Not necessary to enter Run-Test/Idle at all. Other values not implemented. - R - 0 * - dmistat - 11:10 - DMI status: - 0: No error - 1: Reserved - 2..3: Not implemented (DMI accesses always succeed) - R - 0 * - abits - 9:4 - Size of address field in `dmi` register (see {numref}`tab-dmi`) - R - 7 * - version - 3:0 - Conforming to RISC-V Debug specification Version 0.13.2 - R - 1 ::: #### Debug Module Interface Access Register (dmi) The dmi register allows access to the Debug Module Interface (DMI). In the JTAG TAP controller's Update-DR state, the DTM starts the operation specified in the *op* field. In the JTAG TAP controller's Capture-DR state, the DTM updates the *data* field with the result from that operation. :::{note} No status is reported in the op field. Therefore, debuggers should refrain from batching together multiple scans. ::: This register is mapped to the 5-bit JTAG address space. :::{list-table} Debug Module Interface Access Register (dmi, at JTAG 0x11) :name: tab-dmi :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - address - 40:34 - Address used for DMI access. In Update-DR, value used to access DM over DMI. - R/W - 0 * - data - 33:2 - Data to send to DM over DMI during Update-DR, and data returned from DM as result of previous operation. - R/W - 0 * - op - 1:0 - For write: * 0: Ignore data and address (nop) * 1: Read from address (read) * 2: Write data to address (write) * 3: Not implemented (do not use) For read: * 0: Previous operation completed successfully * 1..3: Not implemented (DMI accesses always succeed) - R/W - 0 ::: #### BYPASS Register (BYPASS) The BYPASS register is a standard JTAG register. It is implemented as a 1-bit register which has no functional effect, except adding a 1-bit delay. It allows a debugger to not communicate with this TAP (i.e., bypass it). :::{note} All unused addresses in the 5-bit JTAG address space (i.e., all addresses except 0x01 (`IDCODE`), 0x10 (`dtmcs`), and 0x11 (`dmi`)) select the BYPASS register as well. ::: This register is mapped to the 5-bit JTAG address space. :::{list-table} BYPASS Register (BYPASS, at JTAG 0x1F) :name: tab-bypass :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - bypass - 0 - Bypass - \- - 0 ::: ### Control/Status Registers in Debug Module Interface Address Space {numref}`tab-registers-dmi` Summarizes The Control/Status Registers In The Debug Module Interface Address Space. Registers in the Debug Module Interface address space are accessed through the `dmi` register in the JTAG address space (see [](debugging.md#debug-module-interface-access-register-dmi)). The *address* field of the `dmi` register selects the Debug Module Interface register to be accessed, the *data* field either provides the value to be written to the selected register or captures that register's value, and the *op* field selects the operation to be performed. Addresses shown below are offsets relative to the Debug Module base address. VeeR EL2 supports a single Debug Module with a base address of 0x00. :::{list-table} Registers in Debug Module Interface Address Space :name: tab-registers-dmi :header-rows: 1 * - **DMI Address** - **Name** - **Description** - **Section** * - 0x04 - data0 - Abstract data 0 - [Abstract Data 0 / 1 Registers (data0/1)](debugging.md#abstract-data-0-1-registers-data01) * - 0x05 - data1 - Abstract data 1 - [Abstract Data 0 / 1 Registers (data0/1)](debugging.md#abstract-data-0-1-registers-data01) * - 0x10 - dmcontrol - Debug module control - [System Bus Address 31:0 Register (sbaddress0)](debugging.md#debug-module-control-register-dmcontrol) * - 0x11 - dmstatus - Debug module status - [](debugging.md#debug-module-status-register-dmstatus) * - 0x16 - abstractcs - Abstract control and status - [](debugging.md#abstract-control-and-status-register-abstractcs) * - 0x17 - command - Abstract command - [](debugging.md#abstract-command-register-command) * - 0x18 - abstractauto - Abstract command autoexec - [](debugging.md#abstract-command-autoexec-register-abstractauto) * - 0x38 - sbcs - System bus access control and status - [](debugging.md#system-bus-access-control-and-status-register-sbcs) * - 0x39 - sbaddress0 - System bus address 31:0 - [](debugging.md#system-bus-address-310-register-sbaddress0) * - 0x3C - sbdata0 - System bus data 31:0 - [](debugging.md#system-bus-data-310-register-sbdata0) * - 0x3D - sbdata1 - System bus data 63:32 - [](debugging.md#system-bus-data-6332-register-sbdata1) * - 0x40 - haltsum0 - Halt summary 0 - [](debugging.md#halt-summary-0-register-haltsum0) ::: :::{note} ICCM, DCCM, and PIC memory ranges are only accessible using the access memory abstract command. ::: ### Debug Module Control Register (dmcontrol) The `dmcontrol` register controls the overall Debug Module as well as the hart. :::{note} On any given write, a debugger may only write '1' to either the *resumereq* or *ackhavereset* bit. The other bit must be written to '0'. ::: This register is mapped to the Debug Module Interface address space. :::{list-table} Debug Module Control Register (dmcontrol, at Debug Module Offset 0x10) :name: tab-dmcontrol :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - haltreq - 31 - Halt request: - 0: Clears halt request bit. **Note**: May cancel outstanding halt request. - 1: Sets halt request bit. **Note**: Running hart halts whenever halt request bit is set. - R0/W - 0 * - resumereq - 30 - Resume request: - 0: No effect - 1: Causes hart to resume, if halted **Note**: Also clears resume ack bit for hart. **Note**: Setting *resumereq* bit is ignored if *haltreq* bit is set. - R0/W1 - 0 * - hartreset - 29 - Not implemented (i.e., 0: Deasserted) - R - 0 * - ackhavereset - 28 - Reset core-internal, sticky `havereset` state: - 0: No effect - 1: Clear `havereset` state - R0/W1 - 0 * - Reserved - 27 - Reserved - R - 0 * - hasel - 26 - Selects definition of currently selected harts: * 0: Single currently selected hart (VeeR EL2 is single-thread) - R - 0 * - hartsello - 25:16 - Not implemented (VeeR EL2 is single-thread) - R - 0 * - hartselhi - 15:6 - Not implemented (VeeR EL2 is single-thread) - R - 0 * - Reserved - 5:4 - Reserved - R - 0 * - setresethaltreq - 3 - Not implemented **Note**: *hasresethaltreq* bit in `dmstatus` register ({numref}`tab-dmstatus`) is ‘0’. - R - 0 * - clrresethaltreq - 2 - Not implemented **Note**: *hasresethaltreq* bit in `dmstatus` register ({numref}`tab-dmstatus`) is ‘0’. - R - 0 * - ndmreset - 1 - Controls reset signal from DM to VeeR EL2 core. Signal resets hart, but not DM. To perform a reset, debugger writes ‘1’, and then writes ‘0’ to deassert reset. - R/W - 0 * - dmactive - 0 - Reset signal for Debug Module (DM): - 0: Module's state takes its reset values **Note**: Only *dmactive* bit may be written to value other than its reset value. Writes to all other bits of this register are ignored. - 1: Module functions normally Debugger may pulse this bit low to get Debug Module into known state. **Note**: The core complex’s `dbg_rst_l` signal (see [](complex-ports.md)) resets the Debug Module. It should only be used to reset the Debug Module at power up or possibly with a global reset signal which resets the entire platform. - R/W - 0 ::: #### Debug Module Status Register (dmstatus) The `dmstatus` register reports status for the overall Debug Module as well as the hart. This register is read-only. This register is mapped to the Debug Module Interface address space. :::{list-table} Debug Module Status Register (dmstatus, at Debug Module Offset 0x11) :name: tab-dmstatus :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:23 - Reserved - R - 0 * - impebreak - 22 - Not implemented **Note**: VeeR EL2 does not implement a Program Buffer. - R - 0 * - Reserved - 21:20 - Reserved - R - 0 * - allhavereset - 19 - '1' when hart has been reset and reset has not been acknowledged - R - \- * - anyhavereset - 18 - '1' when hart has been reset and reset has not been acknowledged - R - \- * - allresumeack - 17 - '1' when hart has acknowledged last resume request - R - \- * - anyresumeack - 16 - '1' when hart has acknowledged last resume request - R - \- * - allnonexistent - 15 - Not implemented (VeeR EL2 is single-thread) - R - 0 * - anynonexistent - 14 - Not implemented (VeeR EL2 is single-thread) - R - 0 * - allunavail - 13 - '1' when hart is unavailable [^fn-debugging-1] - R - \- * - anyunavail - 12 - '1' when hart is unavailable [^fn-debugging-1] - R - \- * - allrunning - 11 - '1' when hart is running - R - \- * - anyrunning - 10 - '1' when hart is running - R - \- * - allhalted - 9 - '1' when hart is halted - R - \- * - anyhalted - 8 - '1' when hart is halted - R - \- * - authenticated - 7 - Not implemented (i.e., 1: Always authenticated) - R - 1 * - authbusy - 6 - Not implemented (i.e., 0: Authentication module never busy) - R - 0 * - hasresethaltreq - 5 - Not implemented **Note**: VeeR EL2 implements halt-on-reset with *haltreq* set out of reset method. - R - 0 * - confstrptrvalid - 4 - Not implemented **Note**: VeeR EL2 does not provide information relevant to configuration string. - R - 0 * - version - 3:0 - Debug Module present, conforming to RISC-V Debug specification Version 0.13.2 - R - 2 ::: [^fn-debugging-1]: Hart is in reset or ndmreset bit of dmstatus register is ‘1’. #### Halt Summary 0 Register (haltsum0) Each bit in the `haltsum0` register indicates whether a specific hart is halted or not. Since VeeR EL2 is singlethreaded, only one bit is implemented. :::{note} Unavailable/nonexistent harts are not considered to be halted. ::: This register is read-only. This register is mapped to the Debug Module Interface address space. :::{list-table} Halt Summary 0 Register (haltsum0, at Debug Module Offset 0x40) :name: tab-haltsum0 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:1 - Reserved - R - 0 * - halted - 0 - '1' when hart halted - R - 0 ::: #### Abstract Control and Status Register (abstractcs) The `abstractcs` register provides status information of the abstract command interface and enables clearing of detected command errors. :::{note} Writing this register while an abstract command is executing causes its *cmderr* field to be set to '1' (i.e., 'busy'), if it is '0'. ::: This register is mapped to the Debug Module Interface address space. :::{list-table} Abstract Control and Status Register (abstractcs, at Debug Module Offset 0x16) :name: tab-abstractcs :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:29 - Reserved - R - 0 * - progbufsize - 28:24 - Not implemented **Note**: VeeR EL2 does not implement a Program Buffer. - R - 0 * - Reserved - 23:13 - Reserved - R - 0 * - busy - 12 - Abstract command interface activity: - 0: Abstract command interface idle - 1: Abstract command currently being executed **Note**: ‘Busy’ indication set when command register (see [](debugging.md#abstract-command-register-command)) is written, cleared after command has completed. - R - 0 * - Reserved - 11 - Reserved - R - 0 * - cmderr - 10:8 - Set if abstract command fails. Reason for failure: - 0 (none): No error - 1 (busy): Abstract command was executing when `command`, `abstractcs`, or `abstractauto` register was written, or when `data0` or `data1` register was read or written - 2 (not supported): Requested command or option not supported, regardless of whether hart is running or not (i.e., illegal command, access register command not word-sized or postexec bit set, or access memory command size larger than word) - 3 (exception): Exception occurred while executing abstract command (i.e., illegal register address, address outside of ICCM/DCCM/PIC memory range but in internal memory region, ICCM/DCCM uncorrectable ECC error, or ICCM/PIC access not word-sized) - 4 (halt/resume): Abstract command couldn't execute because hart wasn't in required state (running/halted), or unavailable - 5 (bus): Abstract command failed for SoC memory access due to bus error (e.g., unmapped address, uncorrectable error, incorrect alignment, or unsupported access size) - 6: Reserved - 7 (other): Register or memory access size not 32 bits wide or unaligned **Note**: Bits in this field remain set until cleared by writing ‘111’. **Note**: Next abstract command not started until value is reset to ‘0’. **Note**: Only contains valid value if *busy* is ‘0’. - R/W1C - 0 * - Reserved - 7:4 - Reserved - R - 0 * - datacount - 3:0 - 2 data registers implemented as part of abstract command interface - R - 2 ::: ### Abstract Command Register (command) Writes to the command register `cause` the corresponding abstract command to be executed. Writing this register while an abstract command is executing causes the *cmderr* field in the abstractcs register (see [](debugging.md#abstract-control-and-status-register-abstractcs)) to be set to '1' (i.e., 'busy'), if it is '0'. If the *cmderr* field is non-zero, writes to the command register are ignored. :::{note} A non-zero *cmderr* field inhibits starting a new abstract command to accommodate debuggers which, for performance reasons, may send several commands to be executed in a row without checking the *cmderr* field in between. Checking the *cmderr* field only at the end of a sequence of commands is safe because later commands which might depend on a previous, but failed command are not executed. ::: :::{note} Access register and access memory abstract commands may only be executed when the core is in the debug halt (db-halt) state. If the debugger is requesting the execution of an abstract command while the core is not in the debug halt state, the command is aborted and the *cmderr* field is set to '4' (i.e., 'halt/resume'), if it is '0'. ::: :::{note} The access memory abstract command method provides access to ICCM, DCCM, and PIC memory ranges as well as to SoC memories. ::: This register is mapped to the Debug Module Interface address space. :::{list-table} Abstract Command Register (command, at Debug Module Offset 0x17) :name: tab-command :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - cmdtype - 31:24 - Abstract command type: - 0: Access Register Command - 2: Access Memory Command **Note**: Other values not implemented or reserved for future use. Writing this field to value different than ‘0’ or ‘2’ causes abstract command to fail and *cmderr* field of `abstractcs` register to be set to ‘2’. - R0/W - 0 * - **Access Register Command** - - - - * - Reserved - 23 - Reserved - R - 0 * - aarsize - 22:20 - Register access size: - 2: 32-bit access **Note**: Other size values not implemented. Writing this field to value different than ‘2’ causes abstract command to fail and *cmderr* field of `abstractcs` register to be set to ‘2’, except if transfer is ‘0’. - R/W - 2 * - aarpostincrement - 19 - Access register post-increment control: - 0: No post-increment - 1: After every successful access register command completion, increment *regno* field (wrapping around to 0) - R/W - 0 * - postexec - 18 - Not implemented (i.e., 0: No effect) **Note**: Writing to ‘1’ causes abstract command to fail and *cmderr* field of `abstractcs` register to be set to ‘2’. - R - 0 * - transfer - 17 - Transfer: - 0: Do not perform operation specified by write **Note**: Selection of unimplemented options (except for *aarsize* and *regno* fields) causes cmderr field of `abstractcs` register to be set to ‘2’. - 1: Perform operation specified by write **Note**: Selection of unimplemented options causes abstract command to fail and *cmderr* field of `abstractcs` register to be set to ‘2’. - R - 1 * - write - 16 - Read or write register: - 0 (read): Copy data from register specified in *regno* field into `data0` register ([Abstract Data 0 / 1 Registers (data0/1)](debugging.md#abstract-data-0-1-registers-data0-1)) - 1 (write): Copy data from `data0` register ([Abstract Data 0 / 1 Registers (data0/1)](debugging.md#abstract-data-0-1-registers-data0-1)) into register specified in *regno* field - R0/W - 0 * - regno - 15:0 - Register access: - 0x0000 - 0x0FFF: CSRs - 0x1000 - 0x101F: GPRs - 0x1020 - 0xFFFF: Not implemented or reserved **Note**: Selecting illegal register address causes abstract command to fail and *cmderr* field of `abstractcs` register to be set to ‘3’, except if transfer is ‘0’. - R0/W - 0 * - **Access Memory Command (ICCM, DCCM, PIC, and SoC Memories)** - - - - * - aamvirtual - 23 - Not implemented (i.e., 0: Addresses are physical) **Note**: VeeR EL2 supports physical addresses only. Since physical and virtual address are identical, no error is flagged [^fn-debugging-2] even if written to ‘1’. - R - 0 * - aamsize - 22:20 - Memory access size: - 0: 8-bit access (for DCCM and SoC memories) - 1: 16-bit access (for DCCM and SoC memories) - 2: 32-bit access (for ICCM, DCCM, PIC, and SoC memories) **Note**: Writing this field to value ‘0’ or ‘1’ for ICCM or PIC memory access causes abstract command to fail and *cmderr* field of `abstractcs` register to be set to ‘3’. **Note**: Other size values not implemented. Writing this field to value higher than ‘2’ causes abstract command to fail and *cmderr* field of `abstractcs` register to be set to ‘2’. - R/W - 2 * - aampostincrement - 19 - Access memory post-increment control: - 0: No post-increment - 1: After every successful access memory command completion, increment `data1` register (which contains memory address, see [Abstract Data 0 / 1 Registers (data0/1)](debugging.md#abstract-data-0-1-registers-data0-1)) by number of bytes encoded in *aamsize* field - R/W - 0 * - Reserved - 18:17 - Reserved - R - 0 * - write - 16 - Read or write memory location: * 0 (read): Copy data from memory location specified in data1 register (i.e., address) into data0 register (i.e., data) ([Abstract Data 0 / 1 Registers (data0/1)](debugging.md#abstract-data-0-1-registers-data0-1)) * 1 (write): Copy data from data0 register (i.e., data) into memory location specified in data1 register (i.e., address) ([Abstract Data 0 / 1 Registers (data0/1)](debugging.md#abstract-data-0-1-registers-data0-1)) - R0/W - 0 * - target-specific - 15:14 - Not implemented **Note**: VeeR EL2 does not use target-specific bits. - R - 0 * - Reserved - 13:0 - Reserved - R - 0 ::: [^fn-debugging-2]: The RISC-V Debug specification [[3]](intro.md#ref-3) states that an implementation must fail accesses that it does not support. However, the Debug Task Group community agreed in an email exchange on the group’s reflector as well as in a group meeting that not reporting an error is acceptable for implementations without address translation (i.e., the physical address equals the virtual address). #### Abstract Command Autoexec Register (abstractauto) The `abstractauto` register controls if reading or writing the `data0/1` registers (see [Abstract Data 0 / 1 Registers (data0/1)](debugging.md#abstract-data-0-1-registers-data0-1)) automatically triggers the next execution of the abstract command in the `command` register (see [](debugging.md#abstract-command-register-command)). This feature allows more efficient burst accesses. Writing this register while an abstract command is executing causes the *cmderr* field in the abstractcs register (see [](debugging.md#abstract-control-and-status-register-abstractcs)) to be set to '1' (i.e., 'busy'), if it is '0'. This register is mapped to the Debug Module Interface address space. :::{list-table} Abstract Command Autoexec Register (abstractauto, at Debug Module Offset 0x18) :name: tab-abstractauto :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:2 - Reserved - R - 0 * - autoexecdata1 - 1 - Auto-execution control for `data1` register: * 0: No automatic triggering of abstract command execution * 1: Reading or writing `data1` causes abstract command to be executed again - R/W - 0 * - autoexecdata0 - 0 - Auto-execution control for `data0` register: - 0: No automatic triggering of abstract command execution - 1: Reading or writing `data0` causes abstract command to be executed again - R/W - 0 ::: ### Abstract Data 0 / 1 Registers (data0/1) The `data0/1` registers are basic read/write registers which may be read or changed by abstract commands. :::{note} The *datacount* field of the `abstractcs` register (see {numref}`tab-abstractcs`) indicates that 2 (out of possible 12) registers are implemented in VeeR EL2. ::: The `data0` register sources the value for and provides the return value of an abstract command. The `data1` register provides the address for an access memory abstract command. :::{note} Selecting an address outside of the ICCM, DCCM, or PIC memory range but in one of the core-internal memory regions causes the abstract command to fail and the *cmderr* field of the `abstractcs` register to be set to '3'. Similarly, selecting an unmapped SoC memory address causes the abstract command to fail, provided the SoC responds with a bus error, and the *cmderr* field of the `abstractcs` register to be set to '5'. ::: Accessing these registers while an abstract command is executing causes the *cmderr* field of the `abstractcs` register (see {numref}`tab-abstractcs`) to be set to '1' (i.e., 'busy'), if it was '0'. Attempts to write the `data0/1` registers while the *busy* bit of the abstractcs register (see {numref}`tab-abstractcs`) is set does not change their value. The values in these registers may not be preserved after an abstract command has been executed. The only guarantees on their contents are the ones offered by the executed abstract command. If the abstract command fails, no assumptions should be made about the contents of these registers. These registers are mapped to the Debug Module Interface address space. :::{list-table} Abstract Data 0 / 1 Register (data0/1, at Debug Module Offset 0x04 / 0x05) :name: tab-data-0-1 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - data - 31:0 - Abstract command data: - data0: data value (access register and access memory command) - data1: address (access memory command) - R/W - 0 ::: #### System Bus Access Control and Status Register (sbcs) The `sbcs` register provides controls and status information of the system bus access interface. :::{note} The system bus access method provides access to SoC memories only. Access to ICCM, DCCM, and PIC memory ranges is only available using the access memory abstract command method. ::: :::{note} The operation of the system bus access method does not depend on the core's state. SoC memory locations may be accessed using this method even when the core is running. ::: This register is mapped to the Debug Module Interface address space. :::{list-table} System Bus Access Control and Status Register (sbcs, at Debug Module Offset 0x38) :name: tab-sbcs :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - sbversion - 31:29 - System Bus interface conforms to RISC-V Debug specification, Version 0.13.2 - R - 1 * - Reserved - 28:23 - Reserved - R - 0 * - sbbusyerror - 22 - Set when debugger attempts to read data while a read is in progress, or when debugger initiates a new access while one is still in progress (i.e., while *sbbusy* bit is set). Remains set until explicitly cleared by debugger. **Note**: When set, Debug Module cannot initiate more system bus accesses. - R/W1C - 0 * - sbbusy - 21 - System bus master interface status: * 0: System bus master idle * 1: System bus master busy (Set when read or write access requested, remains set until access fully completed) **Note**: Writes to this register while *sbbusy* bit is set result in undefined behavior. Debugger must not write this register until it reads *sbbusy* bit as ‘0’. **Note**: Bit reflects if system bus master interface is busy, not status of system bus itself. - R - 0 * - sbreadonaddr - 20 - Auto-read on address write: - 0: No auto-read on address write - 1: Every write to `sbaddress0` (see [](debugging.md#system-bus-address-310-register-sbaddress0)) automatically triggers system bus read at new address - R/W - 0 * - sbaccess - 19:17 - Access size for system bus access: - 0: 8-bit access - 1: 16-bit access - 2: 32-bit access - 3: 64-bit access **Note**: Other values not supported. No access performed, *sberror* field set to ‘4’. - R/W - 2 * - sbautoincrement - 16 - Auto-address increment: - 0: No auto-address increment - 1: `sbaddress0` register (see [](debugging.md#system-bus-address-310-register-sbaddress0)) incremented by access size (in bytes) selected in sbaccess field after every successful system bus access - R/W - 0 * - sbreadondata - 15 - Auto-read on data read: - 0: No auto-read on data read - 1: Every read from `sbdata0` register (see [](debugging.md#system-bus-data-310-register-sbdata0)) automatically triggers new system bus read at (possibly auto- incremented) address - R/W - 0 * - sberror - 14:12 - Set when Debug Module's system bus master encounters an error: While this field is non-zero, no more system bus accesses can be initiated by the Debug Module. - 0: No bus error - 1: Not implemented (no timeout) - 2: Bad address accessed - 3: Alignment error - 4: Access of unsupported size requested - 5..7: Not implemented (no other error conditions) **Note**: Bits in this field remain set until cleared by writing ‘111’. **Note**: Debug Module may not initiate next system bus access until value is reset to ‘0’. - R/W1C - 0 * - sbasize - 11:5 - Width of system bus addresses (in bits) - R - 32 * - sbaccess128 - 4 - 128-bit system bus accesses not supported - R - 0 * - sbaccess64 - 3 - 64-bit system bus accesses supported - R - 1 * - sbaccess32 - 2 - 32-bit system bus accesses supported - R - 1 * - sbaccess16 - 1 - 16-bit system bus accesses supported - R - 1 * - sbaccess8 - 0 - 8-bit system bus accesses supported - R - 1 ::: #### System Bus Address 31:0 Register (sbaddress0) The `sbaddress0` register provides the address of the system bus access. If the *sbreadonaddr* bit of the `sbcs` register is '1', writing the `sbaddress0` register triggers a system bus read access from the new address. :::{note} The *sberror* and *sbbusyerror* fields of the `sbcs` register must both be '0' for a system bus read operation to be performed. ::: :::{note} If the system bus master interface is busy (i.e., *sbbusy* bit of the `sbcs` register is '1') when a write access to this register is performed, the *sbbusyerror* bit in the `sbcs` register is set and the access is aborted. ::: This register is mapped to the Debug Module Interface address space. :::{list-table} System Bus Address 31:0 Register (sbaddress0, at Debug Module Offset 0x39) :name: tab-sbaddress0 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - address - 31:0 - System bus address - R/W - 0 ::: #### System Bus Data 31:0 Register (sbdata0) The `sbdata0` register holds the right-justified lower bits for system bus read and write accesses. A successful system bus read updates the `sbdata0/1` registers with the value read from the system bus at the memory location addressed by the sbaddress0 register. If the width of the read access is less than 64 bits, the remaining high bits may take on any value. Reading the `sbdata0` register provides the current value of this register. If the *sbreadondata* bit of the sbcs register is '1', reading this register also triggers a system bus read access which updates the `sbdata0/1` registers with the value read from the memory location addressed by the `sbaddress0` register. Writing the `sbdata0` register triggers a system bus write access which updates the memory location addressed by the `sbaddress0` register with the new values in the `sbdata0/1` registers. :::{note} Only the `sbdata0` register has this behavior. Accessing the `sbdata1` register has no side effects. A debugger must access the `sbdata1` register first, before accessing the sbdata0 register. ::: :::{note} The *sberror* and *sbbusyerror* fields of the `sbcs` register must both be '0' for a system bus read or write operation to be performed. ::: :::{note} If the system bus master interface is busy (i.e., *sbbusy* bit of the sbcs register is '1') when a read or write access to this register is performed, the *sbbusyerror* bit in the `sbcs` register is set and the access is aborted. ::: This register is mapped to the Debug Module Interface address space. :::{list-table} System Bus Data 31:0 Register (sbdata0, at Debug Module Offset 0x3C) :name: tab-sbdata0 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - data - 31:0 - System bus data[31:0] for system bus read and write accesses - R/W - 0 ::: #### System Bus Data 63:32 Register (sbdata1) The `sbdata1` register holds the upper 32 bits of the 64-bit wide system bus for read and write accesses. :::{note} If the system bus master interface is busy (i.e., *sbbusy* bit of the sbcs register is '1') when a read or write access to this register is performed, the *sbbusyerror* bit in the `sbcs` register is set and the access is aborted. ::: This register is mapped to the Debug Module Interface address space. :::{list-table} System Bus Data 63:32 Register (sbdata1, at Debug Module Offset 0x3D) :name: tab-sbdata1 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - data - 31:0 - System bus data[63:32] for system bus read and write accesses - R/W - 0 ::: ### Control/Status Registers in RISC-V CSR Address Space A summary of standard RISC-V control/status registers with platform-specific adaptations in CSR space: * [](debugging.md#trigger-select-register-tselect) * [](debugging.md#trigger-data-1-register-tdata1) * [](debugging.md#match-control-register-mcontrol) * [](debugging.md#trigger-data-2-register-tdata2) * [](debugging.md#debug-control-and-status-register-dcsr) * [](debugging.md#debug-pc-register-dpc) All reserved and unused bits in these control/status registers must be hardwired to '0'. Unless otherwise noted, all read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. #### Trigger Select Register (tselect) :::{note} Since triggers can be used both by Debug Mode and M-mode, the debugger must restore this register if it modified it. ::: This register is mapped to the standard read/write CSR address space. :::{list-table} Trigger Select Register (tselect, at CSR 0x7A0) :name: tab-tselect :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:2 - Reserved - R - 0 * - index - 1:0 - Index of trigger 0..3 **Note**: Triggers 0 and 2 may be chained, triggers 1 and 3 not. - R/W - 0 ::: #### Trigger Data 1 Register (tdata1) This register is mapped to the standard read/write CSR address space. :::{list-table} Trigger Data 1 Register (tdata1, at CSR 0x7A1) :name: tab-tdata1 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - type - 31:28 - See {numref}`tab-mcontrol` below. - R - 2 * - dmode - 27 - See {numref}`tab-mcontrol` below. - See {numref}`tab-mcontrol` below. - See {numref}`tab-mcontrol` below. * - data - 26:0 - See {numref}`tab-mcontrol` below. - See {numref}`tab-mcontrol` below. - See {numref}`tab-mcontrol` below. ::: #### Match Control Register (mcontrol) :::{note} VeeR EL2 does not support triggering on the data of a load or on the opcode of an executed instruction. ::: This register is mapped to the standard read/write CSR address space. :::{list-table} Match Control Register (mcontrol, at CSR 0x7A1) :name: tab-mcontrol :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - type - 31:28 - Address/data match trigger (= mcontrol) - R - 2 * - dmode - 27 - Mode write privileges to `tdata1/2` registers ([](debugging.md#trigger-data-1-register-tdata1) and [](debugging.md#trigger-data-2-register-tdata2)) selected by `tselect` register ([](debugging.md#trigger-select-register-tselect)): - 0: Both Debug Mode and M-mode may write `tdata1/2` registers selected by `tselect` register - 1: Only Debug Mode may write `tdata1/2` registers selected by `tselect` register. Writes from M-mode are ignored. **Note**: Only writable from Debug Mode. - R/W - 0 * - maskmax - 26:21 - {math}`2^{31}` bytes is largest naturally aligned powers-of-two (NAPOT) range supported by hardware when match field is ‘1’. - R - 31 * - hit - 20 - Set by hardware when this trigger matches. Allows to determine which trigger(s) matched. May be set or cleared by trigger’s user at any time. **Note**: For chained triggers, *hit* bit of a matching second trigger is not set unless first trigger matches as well. - R/W - 0 * - select - 19 - Match selection: 0: Perform match on address 1: Perform match on store data value - R/W - 0 * - timing - 18 - Action for this trigger is taken just before instruction that triggered it is committed, but after all preceding instructions are committed. **Note**: No bus transaction is issued for an execute address trigger hit on a load to a side-effect address. - R - 0 * - sizelo - 17:16 - Match size: - 0: Trigger attempts to match against access of any size. - Match against address (if select bit is ‘0’) - Match against store data (if select bit is ‘1’) **Note**: Data is zero extended for byte or halfword stores. **Note**: If *match* bit is ‘1’, the mask in the `tdata2` register is applied independent of the *select* bit value (i.e., in address or data matches). **Note**: Other match size values not implemented. - R - 0 * - action - 15:12 - Action to take when trigger fires: - 0: Raise breakpoint exception (used when software wants to use trigger module without external debugger attached) - 1: Enter Debug Mode (only supported when trigger's *dmode* bit is ‘1’) **Note**: Other values reserved for future use. **Note**: Triggers do not fire if this field is ‘0’ and interrupts are disabled [^fn-debugging-3] (i.e., *mie* bit of `mstatus` standard RISC-V register is ‘0’). - R/W - 0 * - chain - 11 - Trigger chaining: * 0: When this trigger matches, the configured action is taken. * 1: While this trigger does not match, it prevents the trigger with the next index from matching. **Note**: Supported for triggers 0 and 2 only, attempts to set this bit for triggers 1 and 3 are ignored. **Note**: In VeeR EL2, only pairs of triggers (i.e., triggers 0/1 and triggers 2/3) are chainable. **Note**: If *chain* bit of trigger 0/2 is ‘1’, it is chained to trigger 1/3. Only *action* field of trigger 1/3 is used (i.e., *action* field of trigger 0/2 is ignored). The action on second trigger is taken if and only if both triggers in chain match at the same time. **Note**: Because the *chain* bit affects the next trigger, hardware resets it to ‘0’ for `mcontrol` register writes with *dmode* bit of ‘0’ if the next trigger has a dmode bit of ‘1’. In addition, hardware ignores writes to the mcontrol register which would set the *dmode* bit to ‘1’ if the previous trigger has both a *dmode* bit of ‘0’ and a *chain* bit of ‘1’. Debuggers must avoid the latter case by checking the *chain* bit of the previous trigger when writing the `mcontrol` register. - R/W (for triggers 0 and 2) R (for triggers 1 and 3) - 0 * - match - 10:7 - Match control: - 0: Matches when value equals `tdata2` register’s ([](debugging.md#trigger-data-2-register-tdata2)) value [^fn-debugging-4] - 1: Matches when top *M* bits of value match top *M* bits of `tdata2` register’s ([](debugging.md#trigger-data-2-register-tdata2)) value (*M* is 31 minus the index of least-significant bit containing 0 in `tdata2` register) **Note**: Other values not implemented or reserved for future use. - R/W - 0 * - m - 6 - When set, enable this trigger in M-mode - R/W - 0 * - Reserved - 5 - Reserved - R - 0 * - s - 4 - Not implemented - R - 0 * - u - 3 - Not implemented - R - 0 * - execute - 2 - When set, trigger fires on address of executed instruction **Note**: For writes, written to ‘0’ if *select* bit is written to ‘1’. - R/W - 0 * - store - 1 - When set, trigger fires on address or data of store - R/W - 0 * - load - 0 - When set, trigger fires on address of load **Note**: For writes, written to ‘0’ if *select* bit is written to ‘1’. - R/W - 0 ::: [^fn-debugging-3]: To enable native debugging of M-mode code, VeeR EL2 implements the simpler but more restrictive solution of preventing triggers with the *action* field set to '0' (i.e., breakpoint exception) while interrupts are disabled, as described in Section 5.1, 'Native M-Mode Triggers' of the RISC-V Debug specification [[3]](intro.md#ref-3). [^fn-debugging-4]: Bit 0 of tdata2 register is ignored for instruction address matches. #### Trigger Data 2 Register (tdata2) This register is mapped to the standard read/write CSR address space. :::{list-table} Trigger Data 2 Register (tdata2, at CSR 0x7A2) :name: tab-tdata2 :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - value - 31:0 - Match value: - Address or data value for match: - Address of load, store, or executed instruction [^fn-debugging-4] - Data value of store - Match mask (see *match* field of `mcontrol` register ({numref}`tab-mcontrol`) set to '1') - R/W - 0 ::: #### Debug Control and Status Register (dcsr) The `dcsr` register controls the behavior and provides status of the hart in Debug Mode. The RISC-V Debug specification [[3]](intro.md#ref-3), Section 4.8.1 documents some required and several optional features. {numref}`tab-dcsr` describes the required features, the partial support of optional features in VeeR EL2, and indicates features not supported with "Not implemented". :::{note} This register is accessible in **Debug Mode only**. Attempting to access this register in machine mode raises an illegal instruction exception. ::: This register is mapped to the standard read/write CSR address space. :::{list-table} Debug Control and Status Register (dcsr, at CSR 0x7B0) :name: tab-dcsr :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - xdebugver - 31:28 - External debug support exists as described in this chapter and [[3]](intro.md#ref-3) - R - 4 * - Reserved - 27:16 - Reserved - R - 0 * - ebreakm - 15 - * 0: `ebreak` in M-mode behaves as described in RISC-V Privileged specification [[2]](intro.md#ref-2) * 1: `ebreak` in M-mode enters Debug Mode - R/W - 0 * - Reserved - 14 - Reserved - R - 0 * - ebreaks - 13 - Not implemented - R - 0 * - ebreaku - 12 - Not implemented - R - 0 * - stepie - 11 - * 0: Interrupts disabled during single stepping * 1: Interrupts enabled during single stepping * **Note**: Debugger must not change value while hart is running. - R/W - 0 * - stopcount - 10 - * 0: Increment counters as usual * 1: Don't increment any counters (incl. `cycle` and `instret`) while in Debug Mode or on `ebreak` entering Debug Mode (referred value for most debugging scenarios) - R/W - 0 * - stoptime - 9 - Increment timers same as in non-debug mode - R - 0 * - cause - 8:6 - Reason for Debug Mode entry (if multiple reasons in single cycle, set cause to highest priority): * 1: `ebreak` instruction was executed (*priority 3*) * 2: Trigger Module caused a breakpoint exception (*priority 4, highest*) * 3: Debugger or MPC interface (see {numref}`tab-veer-el2-multi-core-debug-ctrl-status-signals`) requested entry to ebug Mode using haltreq (*priority 1*) * 4: Hart single-stepped because *step* was set (*priority 0, lowest*) * 5: Hart halted directly out of reset due to resethaltreq (also acceptable to report '3') (*priority 2*) Other values reserved for future use. - R - 0 * - Reserved - 5 - Reserved - R - 0 * - mprven - 4 - Not implemented (i.e., 0: *mprv* field in `mstatus` register ignored in Debug Mode) - R - 0 * - nmip - 3 - Non-Maskable Interrupt (NMI) pending for hart when set **Note**: NMI may indicate a hardware error condition, reliable debugging may no longer be possible once bit is set. - R - 0 * - step - 2 - When set and not in Debug Mode, hart only executes single instruction and enters Debug Mode. If instruction does not complete due to exception, hart immediately enters Debug Mode before executing trap handler, with appropriate exception registers set. **Note**: Debugger must not change value while hart is running. - R/W - 0 * - prv - 1:0 - Indicates privilege level hart was operating in when Debug Mode was entered (3 = M-mode) - R - 3 ::: #### Debug PC Register (dpc) The `dpc` register provides the debugger information about the program counter (PC) when entering Debug Mode and control where to resume (RISC-V Debug specification [[3]](intro.md#ref-3), Section 4.8.2). Upon entry to Debug Mode, the `dpc` register is updated with the address of the next instruction to be executed. The behavior is described in more detail in {numref}`tab-dpc` below. When resuming, the hart's PC is updated to the address stored in the dpc register. A debugger may write the `dpc` register to change where the hart resumes. :::{note} This register is accessible in **Debug Mode only**. Attempting to access this register in machine mode raises an illegal instruction exception. ::: This register is mapped to the standard read/write CSR address space. :::{list-table} Debug PC Register (dpc, at CSR 0x7B1) :name: tab-dpc :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - dpc - 31:0 - Address captured for: `ebreak`: - Address of `ebreak` instruction Single step: - Address of instruction which would be executed next if not in Debug Mode (i.e., PC + 4 for 32-bit instructions which don't change program flow, destination PC on taken jumps/branches, etc.) Trigger module: If timing (see *timing* bit in `mcontrol` register in {numref}`tab-mcontrol`) is: - 0: Address of instruction which caused trigger to fire - 1: Address of next instruction to be executed when Debug Mode was entered Halt request: - Address of next instruction to be executed when Debug Mode was entered - R/W - 0 ::: ================================================ FILE: docs/source/dual-core-lock-step.md ================================================ # Dual-Core Lockstep (DCLS) This chapter describes the proposed Dual-Core Lockstep functionality and its future implementation in the VeeR EL2 Core, as required by Caliptra 2.0 for side-channel mitigation scenarios, although it may be useful for other applications like rad-hardening or other safety related-scenarios which DCLS is often also used for. ## VeeR EL2 DCLS Overview The lockstep feature will be added as an optional feature of VeeR EL2, disabled by default. If enabled, another copy of the VeeR EL2 CPU core will be additionally instantiated in the design. This second core will be referred to as a Shadow Core in this chapter. The Shadow Core is delayed by a constant, configurable `DELAY` number of clock cycles with regards to the main core. The `DCCM` and `ICCM` memories are not duplicated, and only the main VeeR EL2 CPU core has access to them. The Shadow Core is only supplied with the delayed inputs of the main core, including the relevant `DCCM` and `ICCM` data, without any ability to read from or write to those memories by itself. Similarly, `Icache` is not duplicated with only the main VeeR EL2 CPU core having direct access. The Shadow Core will receive a delayed copy of main core's `Icache` inputs. The copy of main core's `Icache` outputs will be passed into the `Equivalency Checker` to be validated against the Shadow Core's `Icache` outputs. The diagram below outlines the architecture of the proposed solution. ![VeeR DCLS Overview](img/dcls_block_diagram.png) Outputs and the register file from the main core are delayed by `DELAY` cycles and passed to the `Equivalency Checker` for verification against the outputs and the register file of the Shadow Core. ### Error Policy The Dual Core Lockstep module will report an error when detected by asserting a single bit output signal. It is up to the integrator to provide a logic to handle the detected error. The error can be artifficially injected by using [Shadow Core Control](#shadow-core-control) capabilities. The corruption error will be reported always when all of the following requirements are met: * Input and Output signals of both Main Core and Shadow Core differ OR an error injection feature is enabled, * The Shadow Core is out of reset, * The Shadow Core is not disabled. ### Monitored Registers The Shadow Core can have its internal copy of the register file by setting a proper VeeR EL2 configuration flag. Even though every discrepancy between register files of the Main Core and Shadow Core will eventually lead to difference between IOs of these modules, it might take some time for the mismatch to manifest. To determine whether a discrepancy has occurred immediately, the register files from both cores will be compared taking into account a reasonable subset of the VeeR EL2 registers, as defined in the table below: :::{list-table} Monitored VeeR EL2 Registers :header-rows: 0 :name: tab-dcls-monitored-veer-el2-registers :align: center * - **Name** - **Description** * - x1 (ra) - Return address * - x2 (sp) - Stack pointer * - x8 (s0/fp) - Saved register / frame pointer * - x10-x11 (a0-a1) - Function arguments / return values * - x12-17 (a2-7) - Function arguments * - pc - Program Counter * - npc - Next Program Counter * - mstatus - Machine status * - [mie](adaptations.md#machine-interrupt-enable-mie-and-machine-interrupt-pending-mip-registers) - Machine interrupt enable * - mtvec - Machine trap-handler base address * - mscratch - Scratch register for machine trap handlers * - mepc - Machine exception program counter * - [mcause](adaptations.md#machine-cause-register-mcause) - Machine trap cause * - mtval - Machine bad address or instruction * - [mip](adaptations.md#machine-interrupt-enable-mie-and-machine-interrupt-pending-mip-registers) - Machine interrupt pending * - [mcycle](performance.md#standard-risc-v-registers) - Machine cycle counter * - [minstret](performance.md#standard-risc-v-registers) - Machine instructions-retired counter * - [mrac](memory-map.md#region-access-control-register-mrac) - Region access control ::: ```{note} Should the monitored registers be dependent on the VeeR configuration? ``` ### Monitored IOs Since the Shadow Core module must replicate the behavior of the Main Core without any differences, it contains the same input and output ports. Input ports are delayed and routed to the copy of the VeeR EL2 CPU, output ports are compared with the delayed output ports of the Main Core. Refer to {ref}`tab-shadow-core-tracked-signals` for list of ports routed to the Shadow Core. :::{list-table} Core Complex signals tracked by the Shadow Core :name: tab-shadow-core-tracked-signals * - **Signal** - **Dir** - **Description** * - **Clock Enables** - - * - ifu_bus_clk_en - in - IFU master system bus clock enable * - lsu_bus_clk_en - in - LSU master system bus clock enable * - dbg_bus_clk_en - in - Debug master system bus clock enable * - dma_bus_clk_en - in - DMA slave system bus clock enable * - **Reset** - - * - rst_vec[31:1] - in - Core reset vector * - **Interrupts** - - * - nmi_int - in - Non-Maskable Interrupt (async) * - nmi_vec[31:1] - in - Non-Maskable Interrupt vector * - soft_int - in - Standard RISC-V software interrupt (async) * - timer_int - in - Standard RISC-V timer interrupt (async) * - extintsrc_req[pt.PIC_TOTAL_INT:1] - in - External interrupts (async) * - **Core ID** - - * - core_id[31:4] - in - Core ID (mapped to `mhartid[31:4]`) * - **System Bus Interfaces** - - * - ***AXI4*** - - * - ***Instruction Fetch Unit Master AXI4*** - - * - *Write address channel signals* - - * - ifu_axi_awvalid - out - Write address valid (hardwired to 0) * - ifu_axi_awready - in - Write address ready * - ifu_axi_awid[pt.IFU_BUS_TAG-1:0] - out - Write address ID * - ifu_axi_awaddr[31:0] - out - Write address * - ifu_axi_awlen[7:0] - out - Burst length * - ifu_axi_awsize[2:0] - out - Burst size * - ifu_axi_awburst[1:0] - out - Burst type * - ifu_axi_awlock - out - Lock type * - ifu_axi_awcache[3:0] - out - Memory type * - ifu_axi_awprot[2:0] - out - Protection type * - ifu_axi_awqos[3:0] - out - Quality of Service (QoS) * - ifu_axi_awregion[3:0] - out - Region identifier * - *Write data channel signals* - - * - ifu_axi_wvalid - out - Write valid (hardwired to 0) * - ifu_axi_wready - in - Write ready * - ifu_axi_wdata[63:0] - out - Write data * - ifu_axi_wstrb[7:0] - out - Write strobes * - ifu_axi_wlast - out - Write last * - *Write response channel signals* - - * - ifu_axi_bvalid - in - Write response valid * - ifu_axi_bready - out - Write response ready (hardwired to 0) * - ifu_axi_bid[pt.IFU_BUS_TAG-1:0] - in - Response ID tag * - ifu_axi_bresp[1:0] - in - Write response * - *Read address channel signals* - - * - ifu_axi_arvalid - out - Read address valid * - ifu_axi_arready - in - Read address ready * - ifu_axi_arid[pt.IFU_BUS_TAG-1:0] - out - Read address ID * - ifu_axi_araddr[31:0] - out - Read address * - ifu_axi_arlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - ifu_axi_arsize[2:0] - out - Burst size (hardwired to 0b011) * - ifu_axi_arburst[1:0] - out - Burst type (hardwired to 0b01) * - ifu_axi_arlock - out - Lock type (hardwired to 0) * - ifu_axi_arcache[3:0] - out - Memory type (hardwired to 0b1111) * - ifu_axi_arprot[2:0] - out - Protection type (hardwired to 0b100) * - ifu_axi_arqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - ifu_axi_arregion[3:0] - out - Region identifier * - *Read data channel signals* - - * - ifu_axi_rvalid - in - Read valid * - ifu_axi_rready - out - Read ready * - ifu_axi_rid[pt.IFU_BUS_TAG-1:0] - in - Read ID tag * - ifu_axi_rdata[63:0] - in - Read data * - ifu_axi_rresp[1:0] - in - Read response * - ifu_axi_rlast - in - Read last * - ***Load/Store Unit Master AXI4*** - - * - *Write address channel signals* - - * - lsu_axi_awvalid - out - Write address valid * - lsu_axi_awready - in - Write address ready * - lsu_axi_awid[pt.LSU_BUS_TAG-1:0] - out - Write address ID * - lsu_axi_awaddr[31:0] - out - Write address * - lsu_axi_awlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - lsu_axi_awsize[2:0] - out - Burst size * - lsu_axi_awburst[1:0] - out - Burst type (hardwired to 0b01) * - lsu_axi_awlock - out - Lock type (hardwired to 0) * - lsu_axi_awcache[3:0] - out - Memory type * - lsu_axi_awprot[2:0] - out - Protection type (hardwired to 0b000) * - lsu_axi_awqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - lsu_axi_awregion[3:0] - out - Region identifier * - *Write data channel signals* - - * - lsu_axi_wvalid - out - Write valid * - lsu_axi_wready - in - Write ready * - lsu_axi_wdata[63:0] - out - Write data * - lsu_axi_wstrb[7:0] - out - Write strobes * - lsu_axi_wlast - out - Write last * - *Write response channel signals* - - * - lsu_axi_bvalid - in - Write response valid * - lsu_axi_bready - out - Write response ready * - lsu_axi_bid[pt.LSU_BUS_TAG-1:0] - in - Response ID tag * - lsu_axi_bresp[1:0] - in - Write response * - *Read address channel signals* - - * - lsu_axi_arvalid - out - Read address valid * - lsu_axi_arready - in - Read address ready * - lsu_axi_arid[pt.LSU_BUS_TAG-1:0] - out - Read address ID * - lsu_axi_araddr[31:0] - out - Read address * - lsu_axi_arlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - lsu_axi_arsize[2:0] - out - Burst size * - lsu_axi_arburst[1:0] - out - Burst type (hardwired to 0b01) * - lsu_axi_arlock - out - Lock type (hardwired to 0) * - lsu_axi_arcache[3:0] - out - Memory type * - lsu_axi_arprot[2:0] - out - Protection type (hardwired to 0b000) * - lsu_axi_arqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - lsu_axi_arregion[3:0] - out - Region identifier * - *Read data channel signals* - - * - lsu_axi_rvalid - in - Read valid * - lsu_axi_rready - out - Read ready * - lsu_axi_rid[pt.LSU_BUS_TAG-1:0] - in - Read ID tag * - lsu_axi_rdata[63:0] - in - Read data * - lsu_axi_rresp[1:0] - in - Read response * - lsu_axi_rlast - in - Read last * - ***System Bus (Debug) Master AXI4*** - - * - *Write address channel signals* - - * - sb_axi_awvalid - out - Write address valid * - sb_axi_awready - in - Write address ready * - sb_axi_awid[pt.SB_BUS_TAG-1:0] - out - Write address ID (hardwired to 0) * - sb_axi_awaddr[31:0] - out - Write address * - sb_axi_awlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - sb_axi_awsize[2:0] - out - Burst size * - sb_axi_awburst[1:0] - out - Burst type (hardwired to 0b01) * - sb_axi_awlock - out - Lock type (hardwired to 0) * - sb_axi_awcache[3:0] - out - Memory type (hardwired to 0b1111) * - sb_axi_awprot[2:0] - out - Protection type (hardwired to 0b000) * - sb_axi_awqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - sb_axi_awregion[3:0] - out - Region identifier * - *Write data channel signals* - - * - sb_axi_wvalid - out - Write valid * - sb_axi_wready - in - Write ready * - sb_axi_wdata[63:0] - out - Write data * - sb_axi_wstrb[7:0] - out - Write strobes * - sb_axi_wlast - out - Write last * - *Write response channel signals* - - * - sb_axi_bvalid - in - Write response valid * - sb_axi_bready - out - Write response ready * - sb_axi_bid[pt.SB_BUS_TAG-1:0] - in - Response ID tag * - sb_axi_bresp[1:0] - in - Write response * - *Read address channel signals* - - * - sb_axi_arvalid - out - Read address valid * - sb_axi_arready - in - Read address ready * - sb_axi_arid[pt.SB_BUS_TAG-1:0] - out - Read address ID (hardwired to 0) * - sb_axi_araddr[31:0] - out - Read address * - sb_axi_arlen[7:0] - out - Burst length (hardwired to 0b0000_0000) * - sb_axi_arsize[2:0] - out - Burst size * - sb_axi_arburst[1:0] - out - Burst type (hardwired to 0b01) * - sb_axi_arlock - out - Lock type (hardwired to 0) * - sb_axi_arcache[3:0] - out - Memory type (hardwired to 0b0000) * - sb_axi_arprot[2:0] - out - Protection type (hardwired to 0b000) * - sb_axi_arqos[3:0] - out - Quality of Service (QoS) (hardwired to 0b0000) * - sb_axi_arregion[3:0] - out - Region identifier * - *Read data channel signals* - - * - sb_axi_rvalid - in - Read valid * - sb_axi_rready - out - Read ready * - sb_axi_rid[pt.SB_BUS_TAG-1:0] - in - Read ID tag * - sb_axi_rdata[63:0] - in - Read data * - sb_axi_rresp[1:0] - in - Read response * - sb_axi_rlast - in - Read last * - ***DMA Slave AXI4*** - - * - *Write address channel signals* - - * - dma_axi_awvalid - in - Write address valid * - dma_axi_awready - out - Write address ready * - dma_axi_awid[pt.DMA_BUS_TAG-1:0] - in - Write address ID * - dma_axi_awaddr[31:0] - in - Write address * - dma_axi_awlen[7:0] - in - Burst length * - dma_axi_awsize[2:0] - in - Burst size * - dma_axi_awburst[1:0] - in - Burst type * - dma_axi_awprot[2:0] - in - Protection type * - *Write data channel signals* - - * - dma_axi_wvalid - in - Write valid * - dma_axi_wready - out - Write ready * - dma_axi_wdata[63:0] - in - Write data * - dma_axi_wstrb[7:0] - in - Write strobes * - dma_axi_wlast - in - Write last * - *Write response channel signals* - - * - dma_axi_bvalid - out - Write response valid * - dma_axi_bready - in - Write response ready * - dma_axi_bid[pt.DMA_BUS_TAG-1:0] - out - Response ID tag * - dma_axi_bresp[1:0] - out - Write response * - *Read address channel signals* - - * - dma_axi_arvalid - in - Read address valid * - dma_axi_arready - out - Read address ready * - dma_axi_arid[pt.DMA_BUS_TAG-1:0] - in - Read address ID * - dma_axi_araddr[31:0] - in - Read address * - dma_axi_arlen[7:0] - in - Burst length * - dma_axi_arsize[2:0] - in - Burst size * - dma_axi_arburst[1:0] - in - Burst type * - dma_axi_arprot[2:0] - in - Protection type * - *Read data channel signals* - - * - dma_axi_rvalid - out - Read valid * - dma_axi_rready - in - Read ready * - dma_axi_rid[pt.DMA_BUS_TAG-1:0] - out - Read ID tag * - dma_axi_rdata[63:0] - out - Read data * - dma_axi_rresp[1:0] - out - Read response * - dma_axi_rlast - out - Read last * - ***AHB-Lite*** - - * - ***Instruction Fetch Unit Master AHB-Lite*** - - * - *Master signals* - - * - haddr[31:0] - out - System address * - hburst[2:0] - out - Burst type (hardwired to 0b000) * - hmastlock - out - Locked transfer (hardwired to 0) * - hprot[3:0] - out - Protection control * - hsize[2:0] - out - Transfer size * - htrans[1:0] - out - Transfer type * - hwrite - out - Write transfer * - *Slave signals* - - * - hrdata[63:0] - in - Read data * - hready - in - Transfer finished * - hresp - in - Slave transfer response * - ***Load/Store Unit Master AHB-Lite*** - - * - *Master signals* - - * - lsu_haddr[31:0] - out - System address * - lsu_hburst[2:0] - out - Burst type (hardwired to 0b000) * - lsu_hmastlock - out - Locked transfer (hardwired to 0) * - lsu_hprot[3:0] - out - Protection control * - lsu_hsize[2:0] - out - Transfer size * - lsu_htrans[1:0] - out - Transfer type * - lsu_hwdata[63:0] - out - Write data * - lsu_hwrite - out - Write transfer * - *Slave signals* - - * - lsu_hrdata[63:0] - in - Read data * - lsu_hready - in - Transfer finished * - lsu_hresp - in - Slave transfer response * - ***System Bus (Debug) Master AHB-Lite*** - - * - *Master signals* - - * - sb_haddr[31:0] - out - System address * - sb_hburst[2:0] - out - Burst type (hardwired to 0b000) * - sb_hmastlock - out - Locked transfer (hardwired to 0) * - sb_hprot[3:0] - out - Protection control * - sb_hsize[2:0] - out - Transfer size * - sb_htrans[1:0] - out - Transfer type * - sb_hwdata[63:0] - out - Write data * - sb_hwrite - out - Write transfer * - *Slave signals* - - * - sb_hrdata[63:0] - in - Read data * - sb_hready - in - Transfer finished * - sb_hresp - in - Slave transfer response * - ***DMA Slave AHB-Lite*** - - * - *Slave signals* - - * - dma_haddr[31:0] - in - System address * - dma_hburst[2:0] - in - Burst type * - dma_hmastlock - in - Locked transfer * - dma_hprot[3:0] - in - Protection control * - dma_hsize[2:0] - in - Transfer size * - dma_htrans[1:0] - in - Transfer type * - dma_hwdata[63:0] - in - Write data * - dma_hwrite - in - Write transfer * - dma_hsel - in - Slave select * - dma_hreadyin - in - Transfer finished in * - *Master signals* - - * - dma_hrdata[63:0] - out - Read data * - dma_hreadyout - out - Transfer finished * - dma_hresp - out - Slave transfer response * - **Memory interfaces** - - * - ***Data Close-Coupled Memory*** - - * - dccm_clk_override - - * - dccm_ecc_double_error - - * - dccm_ecc_single_error - - * - dccm_rd_addr_hi - - * - dccm_rd_addr_lo - - * - dccm_rd_data_hi - - * - dccm_rd_data_lo - - * - dccm_rden - - * - dccm_wr_addr_hi - - * - dccm_wr_addr_lo - - * - dccm_wr_data_hi - - * - dccm_wr_data_lo - - * - dccm_wren - - * - dec_tlu_core_ecc_disable - out - Disable core ECC * - ***Inctruction Close-Coupled Memory*** - - * - iccm_buf_correct_ecc - - * - iccm_correction_state - - * - iccm_ecc_double_error - - * - iccm_ecc_single_error - - * - iccm_rd_data - - * - iccm_rd_data_ecc - - * - iccm_rden - - * - iccm_rw_addr - - * - iccm_wr_data - - * - iccm_wr_size - - * - iccm_wren - - * - icm_clk_override - - * - ***Instruction Cache Memory*** - - * - ic_debug_addr - - * - ic_debug_rd_data - - * - ic_debug_rd_en - - * - ic_debug_tag_array - - * - ic_debug_way - - * - ic_debug_wr_data - - * - ic_debug_wr_en - - * - ic_eccerr - - * - ic_parerr - - * - ic_premux_data - - * - ic_rd_data - - * - ic_rd_en - - * - ic_rd_hit - - * - ic_rw_addr - - * - ic_sel_premux_data - - * - ic_tag_perr - - * - ic_tag_valid - - * - ic_wr_data - - * - ic_wr_en - - * - ictag_debug_rd_data - - * - **Power Management Unit (PMU) Interface** - - * - i_cpu_halt_req - in - PMU halt request to core (async) * - o_cpu_halt_ack - out - Core acknowledgement for PMU halt request * - o_cpu_halt_status - out - Core halted indication * - i_cpu_run_req - in - PMU run request to core (async) * - o_cpu_run_ack - out - Core acknowledgement for PMU run request * - **Multi-Processor Controller (MPC) Debug Interface** - - * - mpc_debug_halt_req - in - MPC debug halt request to core (async) * - mpc_debug_halt_ack - out - Core acknowledgement for MPC debug halt request * - mpc_debug_run_req - in - MPC debug run request to core (async) * - mpc_debug_run_ack - out - Core acknowledgement for MPC debug run request * - mpc_reset_run_req - in - Core start state control out of reset * - o_debug_mode_status - out - Core in Debug Mode indication * - debug_brkpt_status - out - Hardware/software breakpoint indication * - **Performance Counter Activity** - - * - dec_tlu_perfcnt0 - out - Performance counter 0 incrementing * - dec_tlu_perfcnt1 - out - Performance counter 1 incrementing * - dec_tlu_perfcnt2 - out - Performance counter 2 incrementing * - dec_tlu_perfcnt3 - out - Performance counter 3 incrementing * - **Trace Port** - - * - trace_rv_i_insn_ip[31:0] - out - Instruction opcode * - trace_rv_i_address_ip[31:0] - out - Instruction address * - trace_rv_i_valid_ip - out - Instruction trace valid * - trace_rv_i_exception_ip - out - Exception * - trace_rv_i_ecause_ip[4:0] - out - Exception cause * - trace_rv_i_interrupt_ip - out - Interrupt exception * - trace_rv_i_tval_ip[31:0] - out - Exception trap value * - **Debug Module Interface** - - * - dmi_reg_addr - - * - dmi_reg_en - - * - dmi_reg_rdata - - * - dmi_reg_wdata - - * - dmi_reg_wr_en - - * - **Debug JTAG Port** - - * - jtag_tck - in - JTAG Test Clock (async) * - jtag_tms - in - JTAG Test Mode Select (async, sync to jtag_tck) * - jtag_tdi - in - JTAG Test Data In (async, sync to jtag_tck) * - jtag_trst_n - in - JTAG Test Reset (async) * - jtag_tdo - out - JTAG Test Data Out (async, sync to jtag_tck) * - jtag_id[31:1] - in - JTAG IDCODE register value (bit 0 tied internally to 1) * - **Testing** - - * - scan_mode - in - May be used to enable logic scan test, if implemented (must be ‘0’ for normal core operation) * - mbist_mode - in - May be used to enable MBIST for core-internal memories, if implemented (should be tied to ‘0’ if not used) ::: Signals not compared due to their special meaning: * `clk` - [core complex clock](clocks.md#clocking), * `free_l2clk` - core complex clock always enabled, routed through one clock header, * `active_l2clk` - core complex clock enabled when the core is active, routed through one clock header, * `rst_l` - [core complex reset](clocks.md#core-complex-reset-rst-l), * `dbg_rst_l` - [debug module reset](clocks.md#debug-module-reset-dbg-rst-l). ## Shadow Core Control The DCLS module exposes control logic that can be potentially connected to the external CSR. Specific signals available as the module ports are described in the {ref}`tab-shadow-core-control-signals`. The error injection logic is a part of the Shadow Core and its purpose is to test whether the lockstep module operates correctly and to disable it if needed. Error is injected by asserting the `corruption_detected_o` output signal even if there is no corruption error detected between the Shadow Core and the Main Core. :::{list-table} Shadow Core Control Signals :name: tab-shadow-core-control-signals * - **Signal** - **Direction** - **Width** - **Description** * - disable_corruption_detection_i - input - 1 - Disable all error injection features * - lockstep_err_injection_en_i - input - 1 - Activate an error injection to the Shadow Core * - corruption_detected_o - output - 1 - Indicate that a Shadow Core detected an error (corruption in comparison to the Main Core) ::: ## Configuration ```{warning} The DCLS feature is not supported in Debug Mode. Entering Debug Mode with DCLS enabled will disable DCLS until the next reset. ``` The DCLS feature can be enabled via `-set lockstep_enable=1` option. There are two configuration options: * `-set lockstep_delay={2, 3, 4}` - the delay applied on the Shadow Core between 2 and 4 cycles, * `-set lockstep_regfile_enable=1` - enable exposing the VeeR Register File so the Shadow Core will have an internal copy to compare with the Main Core Register File. The configuration options are ignored and their macros are not generated if the Dual Core Lockstep feature is disabled. ## Validation Plan The DCLS feature will be tested within: * Software DCLS [smoke test](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/testbench/tests/dcls/dcls.c) - covers VeeR CPU core with the Shadow Core execution flow. * RTL `el2_veer_lockstep` [module tests](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/verification/block/dcls) - covers the Shadow Core by itself. :::{list-table} Validation Plan :name: vp-block-name-list-table :header-rows: 0 :align: center * - **Function** - **VeeR EL2 CPU core input corruption detection** * - Reference Document - * - Check description - Verify the panic signal is raised only upon core states' mismatch. Introduce corruption via VeeR EL2 CPU core inputs directed to the Shadow Core. * - Coverage groups - Each output of the VeeR EL2 CPU Core is reached when detecting the mismatch by `Equivalence Checker`. All bounds of configurable delay are reached. * - Assertions - Detection bit is asserted upon encountered corruption. Error behavior follows the error handling policy. No action is taken if no corruption was introduced. * - Comments - * - Test Name - * - - * - **Function** - **VeeR EL2 CPU core output corruption detection** * - Reference Document - * - Check description - Verify the panic signal is raised only upon core states' mismatch. Introduce corruption via the outputs of the main VeeR CPU core directed to `Equivalence Checker` in the Shadow Core. * - Coverage groups - Each output of the VeeR EL2 CPU Core is reached when detecting the mismatch by `Equivalence Checker`. All bounds of configurable delay are reached. * - Assertions - Detection bit is asserted upon encountered corruption. Error behavior follows the relevant error handling policy. No action is taken if no corruption was introduced. * - Comments - * - Test Name - * - - * - **Function** - **Internal state corruption detection** * - Reference Document - * - Check description - Verify the panic signal is raised only upon core states' mismatch. Introduce corruption via exposed registers of the Shadow Core. * - Coverage groups - Each [monitored register](#monitored-registers) is detected by the `Equivalence Checker`. All bounds of configurable delay are reached. * - Assertions - Detection bit is asserted upon encountered corruption. Error behavior follows the relevant error handling policy. No action is taken if no corruption was introduced. * - Comments - The default path will likely be more easily testable with the help of the software testbench. It should be possible to simulate a fault injection via mailbox see: [top_tb.sv](https://github.com/chipsalliance/Cores-VeeR-EL2/blob/795eb588e34b6815033b769d54fcf7cfac4aae3a/testbench/tb_top.sv#L727). * - Test Name - * - - * - **Function** - **DCLS default execution** * - Reference Document - * - Check description - Verify the DCLS feature behavior during non-obstructed execution. * - Coverage groups - * - Assertions - Detection bit is not raised. Detection interrupt is not asserted. The test provides the same results as the VeeR EL2 CPU core without the DCLS feature enabled. * - Comments - It might be beneficial to use a software test with a program that will produce a result that can by easily compared to an alternative flow and also engage the VeeR EL2 core. Consider matrix multiplication. * - Test Name - * - - * - **Function** - **Error reporting** * - Reference Document - * - Check description - Verify error reporting policy upon detected corruption. * - Coverage groups - Each error policy is covered. * - Assertions - * - Comments - * - Test Name - * - - * - **Function** - **Reset** * - Reference Document - * - Check description - Verify the behavior in reset. Ensure normal execution upon leaving reset. * - Coverage groups - * - Assertions - Shadow Core enters reset at the same time the main VeeR core does. Shadow Core exits reset after a predefined delay following the main core. Detected corruption and interrupts are deasserted upon entering the reset. * - Comments - * - Test Name - * - - ::: ================================================ FILE: docs/source/errata.md ================================================ # Errata ## Back-To-Back Write Transactions Not Supported on AHB-Lite Bus * **Description**: The AHB-Lite bus interface for LSU is not optimized for write performance. Each aligned store is issued to the bus as a single write transaction followed by an idle cycle. Each unaligned store is issued to the bus as multiple backto-back byte write transactions followed by an idle cycle. These idle cycles limit the achievable bus utilization for writes. * **Symptoms**: Potential performance impact for writes with AHB-Lite bus. * **Workaround**: None. ## Debug Abstract Command Register May Return Non-Zero Value On Read * **Description**: The RISC-V External Debug specification specifies the abstract command (`command`) register as write-only (see Section 3.14.7 in [[3]](intro.md#ref-3)). However, the VeeR EL2 implementation supports write as well as read operations to this register. This may help a debugger's feature discovery process, but is not fully compliant with the RISC-V External Debug specification. Because the expected return value for reading this register is always zero, it is unlikely that a debugger expecting a zero value would attempt to read it. * **Symptoms**: Reading the debug abstract command (`command`) register may return a non-zero value. * **Workaround**: A debugger should avoid reading the abstract command register if it cannot handle non-zero data. ================================================ FILE: docs/source/error-protection.md ================================================ # Memory Error Protection ## General Description ### Parity Parity is a simple and relatively cheap protection scheme generally used when the corrupted data can be restored from some other location in the system. A single parity check bit typically covers several data bits. Two parity schemes are used: even and odd parity. The total number of '1' bits are counted in the protected data word, including the parity bit. For even parity, the data is deemed to be correct if the total count is an even number. Similarly, for odd parity if the total count is an odd number. Note that double-bit errors cannot be detected. ### Error Correcting Code (ECC) A robust memory hierarchy design often includes ECC functions to detect and, if possible, correct corrupted data. The ECC functions described are made possible by Hamming code, a relatively simple yet powerful ECC code. It involves storing and transmitting data with multiple check bits (parity) and decoding the associated check bits when retrieving or receiving data to detect and correct errors. The ECC feature can be implemented with Hamming based SECDED (Single-bit Error Correction and Double-bit Error Detection) algorithm. The design can use the (39, 32) code - 32 data bits and 7 parity bits depicted in {numref}`fig-ecc-mem-diag` below. In other words, the Hamming code word width is 39 bits, comprised of 32 data bits and 7 check bits. The minimum number of check bits needed for correcting a single-bit error in a 32-bit word is six. The extra check bit expands the function to detect double-bit errors as well. ECC codes may also be used for error detection only if other means exist to correct the data. For example, the Icache stores exact copies of cache lines which are also residing in SoC memory. Instead of correcting corrupted data fetched from the I-cache, erroneous cache lines may also be invalidated in the I-cache and refetched from SoC memory. A SEDDED (Single-bit Error Detection and Double-bit Error Detection) code is sufficient in that case and provides even better protection than a SECDED code since double-bit errors are corrected as well but requires fewer bits to protect each codeword. Note that flushing and refetching is the industry standard mechanism for recovering from I-cache errors, though commonly still referred to as 'SECDED'. :::{figure-md} fig-ecc-mem-diag ![ECC in a Memory System](img/ecc_mem_diag.png) Conceptual Block Diagram – ECC in a Memory System ::: ## Selecting the Proper Error Protection Level Choosing a protection level that is too weak might lead to loss of data or silent data corrupted, choosing a level that is too strong incurs additional chip die area (i.e., cost) and power dissipation. Supporting multiple protection schemes for the same design increases the design and verification effort. Sources of errors can be divided into two major categories: * Hard errors (e.g., stuck-at bits), and * Soft errors (e.g., weak bits, cosmic-induced soft errors) Selecting an adequate error protection level - e.g., none, parity, or ECC -- depends on the probability of an error to occur, which depends on several factors: * Technology node * SRAM structure size * SRAM cell design * Type of stored information * E.g., instructions in I-cache can be refetched, but data might be lost if not adequately protected * Stored information being used again after corruption Typically, a FIT (Failure In Time) rate analysis is done to determine the proper protection level of each memory in a system. This analysis is based on FIT rate information for a given process and SRAM cell design which are typically available from chip manufacturer. Also important is the SRAM array design. The SRAM layout can have an impact on if an error is correctable or not. For example, a single cosmic-induced soft error event may destroy the content of multiple bit cells in an array. If the destroyed bits are covered by the same codeword, the data cannot be corrected or possibly even detected. Therefore, the bits of each codeword should be physically spread in the array as far apart as feasibly possible. In a properly laid out SRAM array, multiple corrupted bits may result in several single-bit errors of different codewords which are correctable. ## Memory Hierarchy {numref}`tab-memory-hierarchy-components-and-protection` summarizes the components of the VeeR EL2 memory hierarchy and their respective protection scheme. :::{list-table} Memory Hierarchy Components and Protection :name: tab-memory-hierarchy-components-and-protection * - **Memory Type** - **Abbreviation** - **Protection** - **Reason/Justification** * - Instruction Cache - I-cache - Parity or SEDDED ECC (data and tag) [^fn-error-protection-1] - Instructions can be refetched if error is detected * - Instruction Closely-Coupled Memory - ICCM - SECDED ECC - - Large SRAM arrays - Data could be modified and is only valid copy * - Data Closely-Coupled Memory - DCCM - SECDED ECC - - Large SRAM arrays - Data could be modified and is only valid copy * - Core-complex-external Memories - SoC memories - SECDED ECC - - Large SRAM arrays - Data could be modified and is only valid copy ::: [^fn-error-protection-1]: Some highly reliable/available applications (e.g., automotive) might want to use an ECC-protected I-cache, instead of parity protection. Therefore, SEDDED ECC protection is optionally provided in VeeR EL2 as well, selectable as a core build argument. Note that the I-cache area increases significantly if ECC protection is used. ## Error Detection and Handling {numref}`tab-error-detection-recovery-logging` summarizes the detection of errors, the recovery steps taken, and the logging of error events for each of the VeeR EL2 memories. :::{note} Memories with parity or ECC protection must be initialized with correct parity or ECC. Otherwise, a read access to an uninitialized memory may report an error. The method of initialization depends on the organization and capabilities of the memory. Initialization might be performed by a memory self-test or depend on firmware to overwrite the entire memory range (e.g., via DMA accesses). ::: :::{note} If the DCCM is uninitialized, a load following a store to the same DCCM address may get incorrect data. If firmware initializes the DCCM, aligned word-sized stores should be used (because they don't check ECC), followed by a fence, before any load instructions to DCCM addresses are executed. ::: Empty fields shall be ignored as they provide structure information for the table :::{list-table} Error Detection, Recovery, and Logging :name: tab-error-detection-recovery-logging * - **Memory Type** - **Detection** - **Recovery** - **Recovery** - **Logging** - **Logging** * - - - **Single-bit Error** - **Double-bit Error** - **Single-bit Error** - **Double-bit Error** * - I-cache - - Each 64-bit chunk of instructions protected with 4 parity bits (one per 16 consecutive bits) or 7 ECC bits - Each cache line tag protected with 1 parity bit or 5 ECC bits - Parity/ECC bits checked in pipeline - - - - * - - - **For parity** - - - * - - - - For instruction and tag parity errors, invalidate all cache lines of set - Refetch cache line from SoC memory - Undetected - - Increment I- cache correctable error counter [^fn-error-protection-2] - If error counter has reached threshold, signal correctable error local interrupt (see [](error-protection.md#i-cache-error-counter-threshold-register-micect)) - No action * - - - **For ECC** - - - * - - - - For instruction and tag single- and double ECC errors, invalidate all cache lines of set - Refetch cache line from SoC memory [^fn-error-protection-3] - - For instruction and tag single- and double ECC errors, invalidate all cache lines of set - Refetch cache line from SoC memory [^fn-error-protection-3] - - Increment I-cache correctable error counter [^fn-error-protection-2] - If error counter has reached threshold, signal correctable error local interrupt (see [](error-protection.md#i-cache-error-counter-threshold-register-micect)) - - Increment I-cache correctable error counter [^fn-error-protection-2] - If error counter has reached threshold, signal correctable error local interrupt (see [](error-protection.md#i-cache-error-counter-threshold-register-micect)) * - ICCM - - Each 32-bit chunk protected with 7 ECC bits - ECC checked in pipeline - - For fetches [^fn-error-protection-4]: - Write corrected data/ECC back to ICCM - Refetch instruction from ICCM [^fn-error-protection-3] - For DMA reads: - Correct error in-line - Write corrected data/ECC back to ICCM - Fatal error [^fn-error-protection-5] (uncorrectable) - - Increment [^fn-error-protection-4] ICCM single- bit error counter - If error counter has reached threshold, signal correctable error local interrupt (see [](error-protection.md#iccm-correctable-error-counter-threshold-register-miccmect)) - - For fetches [^fn-error-protection-5]: - Instruction access fault exception - For DMA reads: - Send error response on DMA slave bus to master * - DCCM - - Each 32-bit chunk protected with 7 ECC bits - ECC checked in pipeline - - Correct error in-line - Write [^fn-error-protection-6] corrected data/ECC back to DCCM - Fatal error [^fn-error-protection-7] (uncorrectable) - - Increment [^fn-error-protection-6] DCCM single- bit error counter - If error counter has reached threshold, signal correctable error local interrupt (see [](error-protection.md#dccm-correctable-error-counter-threshold-register-mdccmect)) - - For loads [^fn-error-protection-7]: - Load access fault exception - For stores [^fn-error-protection-7]: - Store/AMO access fault exception - For DMA reads: - Send error response on DMA slave bus to master * - SoC memories - ECC checked at SoC memory boundary - - Correct error - Send corrected data on bus - Write corrected data/ECC back to SRAM array - - Fatal error (uncorrectable) - Data sent on bus with error indication - Core must ignore sent data - - Increment SoC single-bit error counter local to memory - If error counter has reached threshold, signal external interrupt - - For fetches: - Instruction access fault exception - For loads: - Non-blocking load bus error NMI (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - For stores: - Store bus error NMI (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) ::: General comments: * No address information of each individual correctable error is captured. * Stuck-at faults: * Stuck-at bits would cause the correctable error threshold to be reached relatively quickly but are only reported if interrupts are enabled. * Use MBIST to determine exact location of the bad bit. * Because ICCM single-bit errors on fetches are not in-line corrected, VeeR EL2's ICCM implements two row's worth of redundant memory which is transparently managed in hardware. These extra rows help to avoid that a stuck-at bit may hang the core. [^fn-error-protection-2]: It is unlikely, but possible that multiple I-cache parity/ECC errors are detected on a cache line in a single cycle, however, the Icache single-bit error counter is incremented only by one. [^fn-error-protection-3]: A RFPC (ReFetch PC) flush is performed since in-line correction would create timing issues and require an additional clock cycle as well as a different architecture. [^fn-error-protection-4]: All single-bit errors detected on fetches are corrected, written back to the ICCM, and counted, independent of actual instruction execution. [^fn-error-protection-5]: For oldest instruction in pipeline only. [^fn-error-protection-6]: For load/store accesses, the corrected data is written back to the DCCM and counted only if the load/store instruction retires (i.e., access is non-speculative and has no exception). [^fn-error-protection-7]: For non-speculative accesses only. ## Core Error Counter/Threshold Registers A summary of platform-specific core error counter/threshold control/status registers in CSR space: * [](error-protection.md#i-cache-error-counterthreshold-register-micect) * [](error-protection.md#iccm-correctable-error-counterthreshold-register-miccmect) * [](error-protection.md#dccm-correctable-error-counterthreshold-register-mdccmect) All read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. ### I-Cache Error Counter/Threshold Register (micect) The `micect` register holds the I-cache error counter and its threshold. The *count* field of the `micect` register is incremented, if a parity/ECC error is detected on any of the cache line tags of the set or the instructions fetched from the I-cache. The *thresh* field of the `micect` register holds a pointer to a bit position of the *count* field. If the selected bit of the *count* field transitions from '0' to '1', the threshold is reached, and a correctable error local interrupt (see [](memory-map.md#correctable-error-local-interrupt)) is signaled. Hardware increments the *count* field on a detected error. Firmware can non-destructively read the current *count* and *thresh* values or write to both these fields (e.g., to change the threshold and reset the counter). :::{note} The counter may overflow if not serviced and reset by firmware. ::: :::{note} The correctable error local interrupt is not latched (i.e., "sticky"), but it stays pending until the counter overflows (i.e., as long as the *count* value is equal to or greater than the threshold value (= {math}`2^{thresh}`)). When firmware resets the counter, the correctable error local interrupt condition is cleared. ::: :::{note} The `micect` register is instantiated, accessible, and has the same functional behavior even if the core is built without an I-cache. ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} I-Cache Error Counter/Threshold Register (micect, at CSR 0x7F0) :name: tab-i-cache-error-counter-threshold-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - thresh - 31:27 - I-cache parity/ECC error threshold: - 0..26: Value i selects *count[i]* bit - 27..31: Invalid (when written, mapped by hardware to 26) - R/W - 0 * - count - 26:0 - Counter incremented if I-cache parity/ECC error(s) detected. If *count[thresh]* transitions from '0' to '1', signal correctable error local interrupt (see [](memory-map.md#correctable-error-local-interrupt)). - R/W - 0 ::: ### ICCM Correctable Error Counter/Threshold Register (miccmect) The `miccmect` register holds the ICCM correctable error counter and its threshold. The *count* field of the `miccmect` register is incremented, if a correctable ECC error is detected on either an instruction fetch or a DMA read from the ICCM. The *thresh* field of the `miccmect` register holds a pointer to a bit position of the *count* field. If the selected bit of the *count* field transitions from '0' to '1', the threshold is reached, and a correctable error local interrupt (see [](memory-map.md#correctable-error-local-interrupt)) is signaled. Hardware increments the *count* field on a detected single-bit error. Firmware can non-destructively read the current count and *thresh* values or write to both these fields (e.g., to change the threshold and reset the counter). :::{note} The counter may overflow if not serviced and reset by firmware. ::: :::{note} The correctable error local interrupt is not latched (i.e., "sticky"), but it stays pending until the counter overflows (i.e., as long as the *count* value is equal to or greater than the threshold value (= {math}`2^{thresh}`)). When firmware resets the counter, the correctable error local interrupt condition is cleared. ::: :::{note} DMA accesses while in power management Sleep (pmu/fw-halt) or debug halt (db-halt) state may encounter ICCM single-bit errors. Correctable errors are counted in the `miccmect` error counter irrespective of the core's power state. ::: :::{note} In the unlikely case of a persistent single-bit error in the ICCM on a location needed for execution of the beginning of the ICCM correctable error local interrupt handler and the counter threshold is set to lower than 16 errors, forward progress may not be guaranteed. ::: :::{note} The `miccmect` register is instantiated, accessible, and has the same functional behavior even if the core is built without an ICCM. ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} ICCM Correctable Error Counter/Threshold Register (miccmect, at CSR 0x7F1) :name: tab-iccm-correctable-error-counter-threshold-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - thresh - 31:27 - ICCM correctable ECC error threshold: - 0..26: Value i selects *count[i]* bit - 27..31: Invalid (when written, mapped by hardware to 26) - R/W - 0 * - count - 26:0 - Counter incremented for each detected ICCM correctable ECC error. If *count[thresh]* transitions from '0' to '1', signal correctable error local interrupt (see [](memory-map.md#correctable-error-local-interrupt)). - R/W - 0 ::: ### DCCM Correctable Error Counter/Threshold Register (mdccmect) The `mdccmect` register holds the DCCM correctable error counter and its threshold. The *count* field of the `mdccmect` register is incremented, if a correctable ECC error is detected on either a retired load/store instruction or a DMA read access to the DCCM. The *thresh* field of the `mdccmect` register holds a pointer to a bit position of the *count* field. If the selected bit of the *count* field transitions from '0' to '1', the threshold is reached, and a correctable error local interrupt (see [](memory-map.md#correctable-error-local-interrupt)) is signaled. Hardware increments the *count* field on a detected single-bit error for a retired load or store instruction (i.e., a nonspeculative access with no exception) or a DMA read. Firmware can non-destructively read the current *count* and *thresh* values or write to both these fields (e.g., to change the threshold and reset the counter). :::{note} The counter may overflow if not serviced and reset by firmware. ::: :::{note} The correctable error local interrupt is not latched (i.e., "sticky"), but it stays pending until the counter overflows (i.e., as long as the *count* value is equal to or greater than the threshold value (= {math}`2^{thresh}`)). When firmware resets the counter, the correctable error local interrupt condition is cleared. ::: :::{note} DMA accesses while in power management Sleep (pmu/fw-halt) or debug halt (db-halt) state may encounter DCCM single-bit errors. Correctable errors are counted in the `mdccmect` error counter irrespective of the core's power state. ::: :::{note} The `mdccmect` register is instantiated, accessible, and has the same functional behavior even if the core is built without a DCCM. ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} DCCM Correctable Error Counter/Threshold Register (mdccmect, at CSR 0x7F2) :name: tab-mdccmect * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - thresh - 31:27 - DCCM correctable ECC error threshold: - 0..26: Value i selects *count[i]* bit - 27..31: Invalid (when written, mapped by hardware to 26) - R/W - 0 * - count - 26:0 - Counter incremented for each detected DCCM correctable ECC error. If *count[thresh]* transitions from '0' to '1', signal correctable error local interrupt (see [](memory-map.md#correctable-error-local-interrupt)). - R/W - 0 ::: ================================================ FILE: docs/source/index.md ================================================ # {{project}} ```{toctree} :maxdepth: 2 :numbered: intro overview memory-map error-protection dual-core-lock-step timers power interrupts performance cache debugging core-control adaptations csrs interrupt-priority clocks complex-ports build-args tests errata physical-memory-protection user-mode verification simulation-debugging tock ``` ================================================ FILE: docs/source/interrupt-priority.md ================================================ # Interrupt Priorities {numref}`tab-veer-el2-platform-specific-and-std-risc-v-interrupt-priorities` summarizes the VeeR EL2 platform-specific (Local) and standard RISC-V (External, Software, and Timer) relative interrupt priorities. :::{list-table} VeeR EL2 Platform-specific and Standard RISC-V Interrupt Priorities. Table is sorted from highest Interrupt priority to lowest Interrupt priority :name: tab-veer-el2-platform-specific-and-std-risc-v-interrupt-priorities * - **Interrupt** - **Section** * - *Non-Maskable Interrupt (standard RISC-V)* - [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - *External interrupt (standard RISC-V)* - [](interrupts.md) * - Correctable error (local interrupt) - [](memory-map.md#correctable-error-local-interrupt) * - *Software interrupt (standard RISC-V)* - [](memory-map.md#software-interrupts) * - *Timer interrupt (standard RISC-V)* - [](performance.md#standard-risc-v-registers) * - Internal timer 0 (local interrupt) - [](timers.md#internal-timer-local-interrupts) * - Internal timer 1 (local interrupt) - [](timers.md#internal-timer-local-interrupts) ::: ================================================ FILE: docs/source/interrupts.md ================================================ # External Interrupts See *Chapter 7, Platform-Level Interrupt Controller (PLIC)* in [[2 (PLIC)]](intro.md#ref-2-plic) for general information. :::{note} Even though this specification is modeled to a large extent after the RISC-V PLIC (Platform-Level Interrupt Controller) specification, this interrupt controller is associated with the core, not the platform. Therefore, the more general term PIC (Programmable Interrupt Controller) is used. ::: ## Features The PIC provides these core-level external interrupt features: * Up to 255 global (core-external) interrupt sources (from 1 (highest) to 255 (lowest)) with separate enable control for each source * 15 priority levels (numbered 1 (lowest) to 15 (highest)), separately programmable for each interrupt source * Programmable reverse priority order (14 (lowest) to 0 (highest)) * Programmable priority threshold to disable lower-priority interrupts * Wake-up priority threshold (hardwired to highest priority level) to wake up core from power-saving (Sleep) mode if interrupts are enabled * One interrupt target (RISC-V hart M-mode context) * Support for vectored external interrupts * Support for fast interrupt redirection in hardware (selectable by build argument) * Support for interrupt chaining and nested interrupts * Power reduction feature for disabled external interrupts ## Naming Convention ### Unit, Signal, and Register Naming **S suffix:** Unit, signal, and register names which have an S suffix indicate an entity specific to an interrupt source. **X suffix:** Register names which have an X suffix indicate a consolidated register for multiple interrupt sources. ### Address Map Naming **Control/status register:** A control/status register mapped to either the memory or the CSR address space. **Memory-mapped register:** Register which is mapped to RISC-V's 32-bit memory address space. **Register in CSR address space:** Register which is mapped to RISC-V's 12-bit CSR address space. ## Overview of Major Functional Units ### External Interrupt Source All functional units on the chip which generate interrupts to be handled by the RISC-V core are referred to as external interrupt sources. External interrupt sources indicate an interrupt request by sending an asynchronous signal to the PIC. ### Gateway Each external interrupt source connects to a dedicated gateway. The gateway is responsible for synchronizing the interrupt request to the core's clock domain, and for converting the request signal to a common interrupt request format (i.e., active-high and level-triggered) for the PIC. The PIC core can only handle one single interrupt request per interrupt source at a time. All current SoC IP interrupts are asynchronous and level-triggered. Therefore, the gateway's only function for SoC IP interrupts is to synchronize the request to the core clock domain. There is no state kept in the gateway. A gateway suitable for ASIC-external interrupts must provide programmability for interrupt type (i.e., edge- vs. leveltriggered) as well as interrupt signal polarity (i.e., low-to-high vs. high-to-low transition for edge-triggered interrupts, active-high vs. -low for level-triggered interrupts). For edge-triggered interrupts, the gateway must latch the interrupt request in an interrupt pending (IP) flop to convert the edge- to a level-triggered interrupt signal. Firmware must clear the IP flop while handling the interrupt. :::{note} While an interrupt is disabled, spurious changes of the interrupt source input may be captured in the IP flop. To reduce the probability of reporting spurious interrupts, firmware should clear the IP flop before reenabling interrupts. ::: :::{note} The gateway does not implement any edge-detection logic (e.g., an edge-triggered flop) to convert the interrupt request to a level-triggered interrupt signal (see {numref}`fig-configurable-gatewat-diagram`). Therefore, the interrupt request input signal must be set to the inactive level (i.e., to '0' for an active-high interrupt and to '1' for an active-low interrupt) to avoid an interrupt request being continuously reported as pending, even after the gateway's IP latch has been cleared. Consequently, if the gateway of an unused interrupt request input is programmed to an "active-high" polarity, the interrupt input signal must be tied off to '0'. Similarly, if the polarity is programmed to "active-low", the interrupt input signal must be tied off to '1'. ::: :::{note} For asynchronous interrupt sources, the pulse duration of an interrupt request must be at least two full clock cycles of the receiving (i.e., PIC core) clock domain to guarantee it will be recognized as an interrupt request. Shorter pulses might be dropped by the synchronizer circuit. ::: ### PIC Core The PIC core's responsibility is to evaluate all pending and enabled interrupt requests and to pick the highest-priority request with the lowest interrupt source ID. It then compares this priority with a programmable priority threshold and, to support nested interrupts, the priority of the interrupt handler if one is currently running. If the picked request's priority is higher than both thresholds, it sends an interrupt notification to the core. In addition, it compares the picked request's priority with the wake-up threshold (highest priority level) and sends a wake-up signal to the core, if the priorities match. The PIC core also provides the interrupt source ID of the picked request in a status register. :::{note} Different levels in the evaluation tree may be staged wherever necessary to meet timing, provided that all signals of a request (ID, priority, etc.) are equally staged. ::: ### Interrupt Target The interrupt target is a specific RISC-V hart context. For the VeeR EL2 core, the interrupt target is the M privilege mode of the hart. ## PIC Block Diagram {numref}`fig-pic-block-diagram` depicts a high-level view of the PIC. A simple gateway for asynchronous, level-triggered interrupt sources is shown in {numref}`fig-gateway-for-asynchronous`, whereas {numref}`fig-configurable-gatewat-diagram` depicts conceptually the internal functional blocks of a configurable gateway. {numref}`fig-comparator` shows a single comparator which is the building block to form the evaluation tree logic in the PIC core. :::{figure-md} fig-pic-block-diagram ![PIC Block Diagram](img/pic_diagram.png) PIC Block Diagram ::: :::{note} For R/W control/status registers with double-borders in {numref}`fig-pic-block-diagram`, the outputs of the registers are conditionally bit-wise inverted, depending on the priority order set in the *`priord`* bit of the `mpiccfg` register. This is necessary to support the reverse priority order feature. ::: :::{note} The PIC logic always operates in regular priority order. When in reverse priority order mode, firmware reads and writes the control/status registers with reverse priority order values. The values written to and read from the control/status registers are inverted. Therefore, from the firmware's perspective, the PIC operates in reverse priority order. ::: :::{figure-md} fig-gateway-for-asynchronous ![Gateway for Asynchronous, Level-triggered Interrupt sources](img/gateway.png) Gateway for Asynchronous, Level-triggered Interrupt Sources ::: :::{figure-md} fig-configurable-gatewat-diagram ![Configurable Gateway Diagram](img/gateway_diagram.png) Conceptual Block Diagram of a Configurable Gateway ::: :::{figure-md} fig-comparator ![Comparator](img/comparator.png) Comparator ::: ## Theory Of Operation :::{note} Interrupts must be disabled (i.e., the *`mie`* bit in the standard RISC-V `mstatus` register must be cleared) before changing the standard RISC-V `mtvec` register or the PIC's `meicurpl` and `meipt` registers, or unexpected behavior may occur. ::: ### Initialization The control registers must be initialized in the following sequence: 1. Configure the priority order by writing the *`priord`* bit of the `mpiccfg` register. 2. For each configurable gateway S, set the polarity (*polarity* field) and type (*type* field) in the `meigwctrlS` register and clear the IP bit by writing to the gateway's `meigwclrS` register. 3. Set the base address of the external vectored interrupt address table by writing the *base* field of the `meivt` register. 4. Set the priority level for each external interrupt source S by writing the corresponding *priority* field of the `meiplS` registers. 5. Set the priority threshold by writing *prithresh* field of the `meipt` register. 6. Initialize the nesting priority thresholds by writing '0' (or '15' for reversed priority order) to the *clidpri* field of the `meicidpl` and the *currpri* field of the `meicurpl` registers. 7. Enable interrupts for the appropriate external interrupt sources by setting the *inten* bit of the `meieS` registers for each interrupt source S. ### Regular Operation A step-by-step description of interrupt control and delivery: 1. The external interrupt source S signals an interrupt request to its gateway by activating the corresponding `exintsrc_req[S]` signal. 2. The gateway synchronizes the interrupt request from the asynchronous interrupt source's clock domain to the PIC core clock domain (`pic_clk`). 3. For edge-triggered interrupts, the gateway also converts the request to a level-triggered interrupt signal by setting its internal interrupt pending (IP) bit. 4. The gateway then signals the level-triggered request to the PIC core by asserting its interrupt request signal. 5. The pending interrupt is visible to firmware by reading the corresponding intpend bit of the `meipX` register. 6. With the pending interrupt, the source's interrupt priority (indicated by the priority field of the `meiplS` register) is forwarded to the evaluation logic. 7. If the corresponding interrupt enable (i.e., *inten* bit of the `meieS` register is set), the pending interrupt's priority is sent to the input of the first-level 2-input comparator. 8. The priorities of a pair of interrupt sources are compared: 1. If the two priorities are different, the higher priority and its associated hardwired interrupt source ID are forwarded to the second-level comparator. 1. If the two priorities are the same, the priority and the lower hardwired interrupt source ID are forwarded to the second-level comparator. 9. Each subsequent level of comparators compares the priorities from two comparator outputs of the previous level: 1. If the two priorities are different, the higher priority and its associated interrupt source ID are forwarded to the next-level comparator. 1. If the two priorities are the same, the priority and the lower interrupt source ID are forwarded to the next-level comparator. 10. The output of the last-level comparator indicates the highest priority (maximum priority) and lowest interrupt source ID (interrupt ID) of all currently pending and enabled interrupts. 11. Maximum priority is compared to the higher of the two priority thresholds (i.e., *prithresh* field of the `meipt` and *currpri* field of the `meicurpl` registers): 1. If maximum priority is higher than the two priority thresholds, the `mexintirq` signal is asserted. 1. If maximum priority is the same as or lower than the two priority thresholds, the `mexintirq` signal is deasserted. 12. The `mexintirq` signal's state is then reflected in the meip bit of the RISC-V hart's `mip` register. 13. In addition, maximum priority is compared to the wake-up priority level: 1. If maximum priority is 15 (or 0 for reversed priority order), the wake-up notification (WUN) bit is set. 1. If maximum priority is lower than 15 (or 0 for reversed priority order), the wake-up notification (WUN) bit is not set. 14. The WUN state is indicated to the target hart with the `mhwakeup` signal [^fn-interrupts-1]. 15. When the target hart takes the external interrupt, it disables all interrupts (i.e., clears the *mie* bit of the RISCV hart's `mstatus` register) and jumps to the external interrupt handler. 16. The external interrupt handler writes to the `meicpct`register to trigger the capture of the interrupt source ID of the currently highest-priority pending external interrupt (in the meihap register) and its corresponding priority (in the `meicidpl` register). Note that the captured content of the claimid field of the meihap register and its corresponding priority in the `meicidpl` register is neither affected by the priority thresholds (prithresh field of the meipt and currpri field of the `meicurpl` registers) nor by the core's external interrupt enable bit (meie bit of the RISC-V hart's `mie` register). 17. The handler then reads the meihap register to obtain the interrupt source ID provided in the *claimid* field. Based on the content of the meihap register, the external interrupt handler jumps to the handler specific to this external interrupt source. 18. The source-specific interrupt handler services the external interrupt, and then: 1. For level-triggered interrupt sources, the interrupt handler clears the state in the SoC IP which initiated the interrupt request. 1. For edge-triggered interrupt sources, the interrupt handler clears the IP bit in the source's gateway by writing to the `meigwclrS` register. 19. The clearing deasserts the source's interrupt request to the PIC core and stops this external interrupt source from participating in the highest priority evaluation. 20. In the background, the PIC core continuously evaluates the next pending interrupt with highest priority and lowest interrupt source ID: 1. If there are other interrupts pending, enabled, and with a priority level higher than *prithresh* field of the `meipt` and *currpri* field of the `meicurpl` registers, `mexintirq` stays asserted. 1. If there are no further interrupts pending, enabled, and with a priority level higher than *prithresh* field of the `meipt` and *currpri* field of the `meicurpl` registers, `mexintirq` is deasserted. 21. Firmware may update the content of the `meihap` and `meicidpl` registers by writing to the `meicpct` register to trigger a new capture. [^fn-interrupts-1]: Note that the core is only woken up from the power management Sleep (pmu/fw-halt) state if the `mie` bit of the `mstatus` and the meie bit of the `mie` standard RISC-V registers are both set. ## Support for Vectored External Interrupts :::{note} The RISC-V standard defines support for vectored interrupts down to an interrupt class level (i.e., timer, software, and external interrupts for each privilege level), but not to the granularity of individual external interrupt sources (as described in this section). The two mechanisms are independent of each other and should be used together for lowest interrupt latency. For more information on the standard RISC-V vectored interrupt support, see Section 3.1.7 in [[2]](intro.md#ref-2). ::: The VeeR EL2 PIC implementation provides support for vectored external interrupts. The content of the `meihap` register is a full 32-bit pointer to the specific vector to the handler of the external interrupt source which needs service. This pointer consists of a 22-bit base address (*base*) of the external interrupt vector table, the 8-bit claim ID (*claimid*), and a 2-bit '0' field. The *claimid* field is adjusted with 2 bits of zeros to construct the offset into the vector table containing 32-bit vectors. The external interrupt vector table resides either in the DCCM, SoC memory, or a dedicated flop array in the core. :::{figure-md} fig-vectored-external-interrupts ![Vectored External Interrupts](img/vei.png) Vectored External Interrupts ::: {numref}`fig-vectored-external-interrupts` depicts the steps from taking the external interrupt to starting to execute the interrupt source-specific handler. When the core takes an external interrupt, the initiated external interrupt handler executes the following operations: 1. Save register(s) used in this handler on the stack 2. Store to the `meicpct` control/status register to capture a consistent claim ID / priority level pair 3. Load the `meihap` control/status register into *`regX`* 4. Load memory location at address in *`regX`* into *`regY`* 5. Jump to address in *`regY`* (i.e., start executing the interrupt source-specific handler) :::{note} Two registers (*`regX`* and *`regY`*) are shown above for clarification only. The same register can be used. ::: :::{note} The interrupt source-specific handler must restore the register(s) saved in step 1. above before executing the `mret` instruction. ::: It is possible in some corner cases that the captured claim ID read from the meihap register is 0 (i.e., no interrupt request is pending). To keep the interrupt latency at a minimum, the external interrupt handler above should not check for this condition. Instead, the pointer stored at the base address of the external interrupt vector table (i.e., pointer 0) must point to a 'no-interrupt' handler, as shown in {numref}`fig-vectored-external-interrupts` above. That handler can be as simple as executing a return from interrupt (i.e., `mret`) instruction. Note that it is possible for multiple interrupt sources to share the same interrupt handler by populating their respective interrupt vector table entries with the same pointer to that handler. ### Fast Interrupt Redirect VeeR EL2 provides fast interrupt handing through interrupt redirection by hardware. The fast interrupt redirect feature is configured with a build argument to the core. If this feature is instantiated, hardware automatically captures a consistent claim ID / priority level pair once at least one qualifying external interrupt is pending and external interrupts are enabled (i.e., the *meie* bit in the `mie` register and the *mie* bit in the `mstatus` register are set). Following conceptually the same flow as shown in {numref}`fig-vectored-external-interrupts`, hardware uses the content of the meihap register to lookup the start address of the corresponding Interrupt Service Routine (ISR) by stalling decode and creating a bubble in the LSU pipeline. This bubble allows the core to access the external interrupt vector table in the DCCM to get the start address of the interrupt source-specific ISR. Once the start address of the ISR is known, hardware creates an interrupt flush and redirects directly to the corresponding ISR. If the hardware lookup of the ISR's start address fails for any reason, a non-maskable interrupt (NMI, see [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector)) is taken. The reason for the lookup failure is reported in the mcause register (see {numref}`tab-machine-cause-register`) so firmware may determine which error condition has occurred. The fast-interrupt-redirect-related NMI failure modes are: * Double-bit uncorrectable ECC error on access (`mcause` value: 0xF000_1000) * Access not entirely contained within the DCCM, but within DCCM region (`mcause` value: 0xF000_1001) * Access to non-DCCM region (`mcause` value: 0xF000_1002) :::{note} The fast interrupt redirect mechanism is independent of the standard RISC-V direct and vectored interrupt modes. However, when fast interrupt redirect is enabled, external interrupts are bypassing the standard RISC-V interrupt mechanism. All other interrupts are still following the standard flow. ::: :::{note} The fast interrupt redirect feature is not compatible with interrupt chaining concept described in [](interrupts.md#interrupt-chaining) below. The `meicpct` register (see [External Interrupt Claim ID / Priority Level Capture Trigger Register (meicpct)](interrupts.md#external-interrupt-claim-id-priority-level-capture-trigger-register-meicpct)) to capture the latest interrupt evaluation result is not present if the fast interrupt redirect mechanism is instantiated because the capturing of the claim ID / priority level pair is initiated in hardware, instead of firmware. ::: ## Interrupt Chaining {numref}`fig-interrupt-chaining` depicts the concept of chaining interrupts. The goal of chaining is to reduce the overhead of pushing and popping state to and from the stack while handling a series of Interrupt Service Routines (ISR) of the same priority level. The first ISR of the chain saves the state common to all interrupt handlers of this priority level to the stack and then services its interrupt. If this handler needs to save additional state, it does so immediately after saving the common state and then restores only the additional state when done. At the end of the handler routine, the ISR writes to the `meicpct` register to capture the latest interrupt evaluation result, then reads the meihap register to determine if any other interrupts of the same priority level are pending. If no, it restores the state from the stack and exits. If yes, it immediately jumps into the next interrupt handler skipping the restoring of state in the finished handler as well as the saving of the same state in the next handler. The chaining continues until no other ISRs of the same priority level are pending, at which time the last ISR of the chain restores the original state from the stack again. :::{note} Interrupt chaining is not compatible with the fast interrupt redirect feature (see [](interrupts.md#fast-interrupt-redirect)). If the fast interrupt redirect mechanism is instantiated, interrupt chaining cannot be used. ::: :::{figure-md} fig-interrupt-chaining ![Interrupt Chaining](img/interrupt_chaining.png) Concept of Interrupt Chaining ::: ## Interrupt Nesting Support for multiple levels of nested interrupts helps to provide a more deterministic interrupt latency at higher priority levels. To achieve this, a running interrupt handler with lower priority must be preemptable by a higher-priority interrupt. The state of the preempted handler is saved before the higher priority interrupt is executed, so that it can continue its execution at the point it was interrupted. VeeR EL2 and its PIC provide supported for up to 15 nested interrupts, one interrupt handler at each priority level. The conceptual steps of nesting are: 1. The external interrupt is taken as described in step 15. of [](interrupts.md#regular-operation). When the core takes the external interrupt, it automatically disables all interrupts. 2. The external interrupt handler executes the following steps to get into the source-specific interrupt handler, as described in [](interrupts.md#support-for-vectored-external-interrupts): ``` st meicpct // atomically captures winning claim ID and priority level ld meihap // get pointer to interrupt handler starting address ld isr_addr // load interrupt handler starting address jmp isr_addr // jump to source-specific interrupt handler ``` 3. The source-specific interrupt handler then saves the state of the code it interrupted (including the priority level in case it was an interrupt handler) to the stack, sets the priority threshold to its own priority, and then reenables interrupts: ``` push mepc, mstatus, mie, … push meicurpl // save interrupted code's priority level ld meicidpl // read interrupt handler's priority level st meicurpl // change threshold to handler's priority mstatus.mei=1 // reenable interrupts ``` 4. Any external interrupt with a higher priority can now safely preempt the currently executing interrupt handler. 5. Once the interrupt handler finished its task, it disables any interrupts and restores the state of the code it interrupted: ``` mstatus.mei=0 // disable all interrupts pop meicurpl // get interrupted code's priority level st meicurpl // set threshold to previous priority pop mepc, mstatus, mie, … mret // return from interrupt, reenable interrupts ``` 6. The interrupted code continues to execute. ## Power Reduction The synchronizer and interrupt capture flops in the gateway of each external interrupt source are clocked every clock cycle even if the external interrupt request input signal is not changing. These few flops cumulatively may consume a noticeable amount of the overall power of the VeeR EL2 core. VeeR EL2 implements a clock gating feature which turns off the clock to the synchronizer and interrupt capture flops for disabled external interrupt to reduce power consumption. However, the overhead to clock gate the flops associated with a single external interrupt source is significant enough that the potential power savings would be considerably reduced. Therefore, to maximize the power reduction, the gateways of four external interrupt sources are clock gated together as a group (i.e., external interrupt sources 1..3 (since 0 is not a valid interrupt source), 4..7, 8..11, and so on). If at least one external interrupt of a group is enabled, the synchronizer and interrupt capture flops of all four gateways in that group are clocked every clock cycle. But if all four external interrupts of a group are disabled, the synchronizer and interrupt capture flops of all four gateways in that group are clock gated. However, this change in functionality of the PIC has a software-visible impact. The current status of pending external interrupt requests which are disabled may no longer be visible in the `meipX` registers (see [](interrupts.md#external-interrupt-pending-registers-meipx)). Depending on the interrupt servicing method, this may be of no consequence. However, for example, reliably polling the interrupt status of disabled interrupts periodically is no longer possible. The *picio* bit of the `mcgc` register (see {numref}`tab-clock-gating-cr`) controls this power saving feature. Setting the *picio* control bit to '0' turns this feature on. Note that the default value of this clock gating feature is off (i.e., the *picio* bit is '1'). If the current status of pending external interrupt requests must be continuously reported in the meipX registers even for external interrupts which are disabled, this feature must remain turned off. ## Performance Targets The target latency through the PIC, including the clock domain crossing latency incurred by the gateway, is 4 core clock cycles. ## Configurability Typical implementations require fewer than 255 external interrupt sources. Code should only be generated for functionality needed by the implementation. ### Rules * The IDs of external interrupt sources must start at 1 and be contiguous. * All unused register bits must be hardwired to '0'. ### Build Arguments The PIC build arguments are: * **PIC base address for memory-mapped control/status registers (PIC_base_addr)** * See [](build-args.md#memory-related-build-arguments) * **Number of external interrupt sources** * Total interrupt sources (RV_PIC_TOTAL_INT): 2..255 ### Impact on Generated Code #### External Interrupt Sources The number of required external interrupt sources has an impact on the following: * General impact: * Signal pins: * `extintsrc_req[S]` * Registers: * `meiplS` * `meipX` * Logic: * Gateway `S` * Target PIC core impact: * Registers: * `meieS` * Logic: * Gating of priority level with interrupt enable * Number of first-level comparators * Unnecessary levels of the comparator tree #### Further Optimizations Register fields, bus widths, and comparator MUXs are sized to cover the maximum external interrupt source IDs of 255. For approximately every halving of the number of interrupt sources, it would be possible to reduce the number of register fields holding source IDs, bus widths carrying source IDs, and source ID MUXs in the comparators by one. However, the overall reduction in logic is quite small, so it might not be worth the effort. ## PIC Control/Status Registers A summary of the PIC control/status registers in CSR address space: * [](interrupts.md#external-interrupt-priority-threshold-register-meipt) * [](interrupts.md#external-interrupt-vector-table-register-meivt) * [](interrupts.md#external-interrupt-handler-address-pointer-register-meihap) * [External Interrupt Claim ID / Priority Level Capture Trigger Register (meicpct)](interrupts.md#external-interrupt-claim-id-priority-level-capture-trigger-register-meicpct) * [](interrupts.md#external-interrupt-claim-ids-priority-level-register-meicidpl) * [](interrupts.md#external-interrupt-current-priority-level-register-meicurpl) A summary of the PIC memory-mapped control/status registers: * [](interrupts.md#pic-configuration-register-mpiccfg) * [](interrupts.md#external-interrupt-priority-level-registers-meipls) * [](interrupts.md#external-interrupt-pending-registers-meipx) * [](interrupts.md#external-interrupt-enable-registers-meies) * [](interrupts.md#external-interrupt-gateway-configuration-registers-meigwctrls) * [](interrupts.md#external-interrupt-gateway-clear-registers-meigwclrs) All reserved and unused bits in these control/status registers must be hardwired to '0'. Unless otherwise noted, all read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. :::{note} All memory-mapped register writes must be followed by a fence instruction to enforce ordering and synchronization. ::: :::{note} All memory-mapped control/status register accesses must be word-sized and word-aligned. Non-word sized/aligned loads cause a load access fault exception, and non-word sized/aligned stores cause a store/AMO access fault exception. ::: :::{note} Accessing unused addresses within the 32KB PIC address range do not trigger an unmapped address exception. Reads to unmapped addresses return 0, writes to unmapped addresses are silently dropped. ::: ### PIC Configuration Register (mpiccfg) The PIC configuration register is used to select the operational parameters of the PIC. This 32-bit register is an idempotent memory-mapped control register. :::{list-table} PIC Configuration Register (mpiccfg, at PIC_base_addr+0x3000) :name: tab-pic-configuration-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:1 - Reserved - R - 0 * - priord - 0 - Priority order: - 0: RISC-V standard compliant priority order (0=lowest to 15=highest) - 1: Reverse priority order (15=lowest to 0=highest) - R/W - 0 ::: ### External Interrupt Priority Level Registers (meiplS) There are 255 priority level registers, one for each external interrupt source. Implementing individual priority level registers allows a debugger to autonomously discover how many priority level bits are supported for this interrupt source. Firmware must initialize the priority level for each used interrupt source. Firmware may also read the priority level. :::{note} The read and write paths between the core and the `meiplS` registers must support direct and inverted accesses, depending on the priority order set in the *priord* bit of the `mpiccfg` register. This is necessary to support the reverse priority order feature. ::: These 32-bit registers are idempotent memory-mapped control registers. :::{list-table} External Interrupt Priority Level Register S=1..255 (meiplS, at PIC_base_addr+S*4) :name: tab-external-interrupt-priority-level-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:4 - Reserved - R - 0 * - priority - 3:0 - External interrupt priority level for interrupt source ID S - RISC-V standard compliant priority order: - 0: Never interrupt - 1..15: Interrupt priority level (1 is lowest, 15 is highest) - Reverse priority order: - 15: Never interrupt - 14..0: Interrupt priority level (14 is lowest, 0 is highest) - R/W - 0 ::: ### External Interrupt Pending Registers (meipX) Eight external interrupt pending registers are needed to report the current status of up to 255 independent external interrupt sources. Each bit of these registers corresponds to an interrupt pending indication of a single external interrupt source. These registers only provide the status of pending interrupts and cannot be written. :::{note} In VeeR EL2, by default, the status of disabled external interrupt requests are continuously reported in these registers. To reduce power, the gateway's synchronizer and interrupt capture flops of disabled external interrupts may be gated (see [](interrupts.md#power-reduction)). However, if an up-to-date status of all pending interrupt requests is important, this clock gating feature controlled by the *picio* bit in the `mcgc` register (see {numref}`tab-clock-gating-cr`) must remain off. ::: These 32-bit registers are idempotent memory-mapped status registers. :::{list-table} External Interrupt Pending Register X=0..7 (meipX, at PIC_base_addr+0x1000+X*4) :name: tab-external-interrupt-pending-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - `X = 0, Y = 1..31 and X = 1..7, Y = 0..31` - - - - * - intpendX*32+Y - Y - External interrupt pending for interrupt source ID X*32+Y: - 0: Interrupt not pending - 1: Interrupt pending - R - 0 * - `X = 0, Y = 0` - - - - * - Reserved - 0 - Reserved - R - 0 ::: ### External Interrupt Enable Registers (meieS) Each of the up to 255 independently controlled external interrupt sources has a dedicated interrupt enable register. Separate registers per interrupt source were chosen for ease-of-use and compatibility with existing controllers. :::{note} Not packing together interrupt enable bits as bit vectors results in context switching being a more expensive operation. ::: These 32-bit registers are idempotent memory-mapped control registers. :::{list-table} External Interrupt Enable Register *S=1..255* (meieS, at PIC_base_addr+0x2000+S*4) :name: tab-external-interrupt-enable-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:1 - Reserved - R - 0 * - inten - 0 - External interrupt enable for interrupt source ID S: - 0: Interrupt disabled - 1: Interrupt enabled - R/W - 0 ::: ### External Interrupt Priority Threshold Register (meipt) The `meipt` register is used to set the interrupt target's priority threshold. Interrupt notifications are sent to a target only for external interrupt sources with a priority level strictly higher than this target's threshold. Hosting the threshold in a separate register allows a debugger to autonomously discover how many priority threshold level bits are supported. :::{note} The read and write paths between the core and the `meipt` register must support direct and inverted accesses, depending on the priority order set in the *priord* bit of the `mpiccfg` register. This is necessary to support the reverse priority order feature. ::: This 32-bit register is mapped to the non-standard read/write CSR address space. :::{list-table} External Interrupt Priority Threshold Register (`meipt`, at CSR 0xBC9) :name: tab-external-interrupt-priority-threshold-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:4 - Reserved - R - 0 * - prithresh - 3:0 - External interrupt priority threshold: - RISC-V standard compliant priority order: - 0: No interrupts masked - 1..14: Mask interrupts with priority strictly lower than or equal to this threshold - 15: Mask all interrupts - Reverse priority order: - 15: No interrupts masked - 14..1: Mask interrupts with priority strictly lower than or equal to this threshold - 0: Mask all interrupts - R/W - 0 ::: ### External Interrupt Vector Table Register (meivt) The `meivt` register is used to set the base address of the external vectored interrupt address table. The value written to the *base* field of the meivt register appears in the *base* field of the `meihap` register. This 32-bit register is mapped to the non-standard read-write CSR address space. :::{list-table} External Interrupt Vector Table Register (meivt, at CSR 0xBC8) :name: tab-external-interrupt-vector-table-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - base - 31:10 - Base address of external interrupt vector table - R/W - 0 * - Reserved - 9:0 - Reserved - R - 0 ::: ### External Interrupt Handler Address Pointer Register (meihap) The meihap register provides a pointer into the vectored external interrupt table for the highest-priority pending external interrupt. The winning claim ID is captured in the *claimid* field of the meihap register when firmware writes to the `meicpct` register to claim an external interrupt. The priority level of the external interrupt source corresponding to the *claimid* field of this register is simultaneously captured in the *clidpri* field of the `meicidpl` register. Since the PIC core is constantly evaluating the currently highest-priority pending interrupt, this mechanism provides a consistent snapshot of the highest-priority source requesting an interrupt and its associated priority level. This is important to support nested interrupts. The `meiha`p register contains the full 32-bit address of the pointer to the starting address of the specific interrupt handler for this external interrupt source. The external interrupt handler then loads the interrupt handler's starting address and jumps to that address. Alternatively, the external interrupt source ID indicated by the *claimid* field of the `meihap` register may be used by the external interrupt handler to calculate the address of the interrupt handler specific to this external interrupt source. :::{note} The *base* field in the meihap register reflects the current value of the *base* field in the `meivt` register. I.e., *base* is not stored in the `meihap` register. ::: This 32-bit register is mapped to the non-standard read-only CSR address space. :::{list-table} External Interrupt Handler Address Pointer Register (meihap, at CSR 0xFC8) :name: tab-external-interrupt-handler-address-pointer-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - base - 31:10 - Base address of external interrupt vector table (i.e., *base* field of `meivt` register) - R - 0 * - claimid - 9:2 - External interrupt source ID of highest-priority pending interrupt (i.e., lowest source ID with highest priority) - R - 0 * - 00 - 1:0 - Must read as '00' - R - 0 ::: ### External Interrupt Claim ID / Priority Level Capture Trigger Register (meicpct) The `meicpct` register is used to trigger the simultaneous capture of the currently highest-priority interrupt source ID (in the *claimid* field of the `meihap` register) and its corresponding priority level (in the *clidpri* field of the `meicidpl` register) by writing to this register. Since the PIC core is constantly evaluating the currently highest-priority pending interrupt, this mechanism provides a consistent snapshot of the highest-priority source requesting an interrupt and its associated priority level. This is important to support nested interrupts. :::{note} The `meicpct` register to capture the latest interrupt evaluation result is not present (i.e., an invalid CSR address) if the fast interrupt redirect mechanism (see [](interrupts.md#fast-interrupt-redirect)) is instantiated. With that feature, capturing the claim ID / priority level pair is initiated in hardware, instead of firmware. ::: The `meicpct` register has WAR0 (Write Any value, Read 0) behavior. Writing '0' is recommended. :::{note} The `meicpct` register does not have any physical storage elements associated with it. It is write-only and solely serves as the trigger to simultaneously capture the winning claim ID and corresponding priority level. ::: This 32-bit register is mapped to the non-standard read/write CSR address space. :::{list-table} External Interrupt Claim ID / Priority Level Capture Trigger Register (`meicpct`, at CSR 0xBCA) :name: tab-external-interrupt-claim-id * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:0 - Reserved - R0/WA - 0 ::: ### External Interrupt Claim ID's Priority Level Register (meicidpl) The `meicidpl` register captures the priority level corresponding to the interrupt source indicated in the *claimid* field of the `meihap` register when firmware writes to the `meicpct` register. Since the PIC core is constantly evaluating the currently highest-priority pending interrupt, this mechanism provides a consistent snapshot of the highest-priority source requesting an interrupt and its associated priority level. This is important to support nested interrupts. :::{note} The read and write paths between the core and the `meicidpl` register must support direct and inverted accesses, depending on the priority order set in the *priord* bit of the `mpiccfg` register. This is necessary to support the reverse priority order feature. ::: This 32-bit register is mapped to the non-standard read/write CSR address space. :::{list-table} External Interrupt Claim ID’s Priority Level Register (`meicidpl`, at CSR 0xBCB) :name: tab-external-interrupt-claim-id-priority-level-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:4 - Reserved - R - 0 * - clidpri - 3:0 - Priority level of preempting external interrupt source (corresponding to source ID read from *claimid* field of `meihap` register) - R/W - 0 ::: ### External Interrupt Current Priority Level Register (meicurpl) The `meicurpl` register is used to set the interrupt target's priority threshold for nested interrupts. Interrupt notifications are signaled to the core only for external interrupt sources with a priority level strictly higher than the thresholds indicated in this register and the `meipt` register. The `meicurpl` register is written by firmware, and not updated by hardware. The interrupt handler should read its own priority level from the *clidpri* field of the `meicidpl` register and write it to the *currpri* field of the `meicurpl` register. This avoids potentially being interrupted by another interrupt request with lower or equal priority once interrupts are reenabled. :::{note} Providing the `meicurpl` register in addition to the meipt threshold register enables an interrupt service routine to temporarily set the priority level threshold to its own priority level. Therefore, only new interrupt requests with a strictly higher priority level are allowed to preempt the current handler, without modifying the longer-term threshold set by firmware in the `meipt` register. ::: :::{note} The read and write paths between the core and the `meicurpl` register must support direct and inverted accesses, depending on the priority order set in the *priord* bit of the `mpiccfg` register. This is necessary to support the reverse priority order feature. ::: This 32-bit register is mapped to the non-standard read/write CSR address space. :::{list-table} External Interrupt Current Priority Level Register (meicurpl, at CSR 0xBCC) :name: tab-external-interrupt-current-priority-level-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:4 - Reserved - R - 0 * - currpri - 3:0 - Priority level of current interrupt service routine (managed by firmware) - R/W - 0 ::: ### External Interrupt Gateway Configuration Registers (meigwctrlS) Each configurable gateway has a dedicated configuration register to control the interrupt type (i.e., edge- vs. level-triggered) as well as the interrupt signal polarity (i.e., low-to-high vs. high-to-low transition for edge-triggered interrupts, active-high vs. -low for level-triggered interrupts). :::{note} A register is only present for interrupt source S if a configurable gateway is instantiated. ::: These 32-bit registers are idempotent memory-mapped control registers. :::{list-table} External Interrupt Gateway Configuration Register S=1..255 (meigwctrlS, at PIC_base_addr+0x4000+S*4) :name: tab-external-interrupt-gateway-configuration-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:2 - Reserved - R - 0 * - type - 1 - External interrupt type for interrupt source ID S: - 0: Level-triggered interrupt - 1: Edge-triggered interrupt - R/W - 0 * - polarity - 0 - External interrupt polarity for interrupt source ID S: - 0: Active-high interrupt - 1: Active-low interrupt - R/W - 0 ::: ### External Interrupt Gateway Clear Registers (meigwclrS) Each configurable gateway has a dedicated clear register to reset its interrupt pending (IP) bit. For edge-triggered interrupts, firmware must clear the gateway's IP bit while servicing the external interrupt of source ID S by writing to the `meigwclrS` register. :::{note} A register is only present for interrupt source S if a configurable gateway is instantiated. ::: The `meigwclrS` register has WAR0 (Write Any value, Read 0) behavior. Writing '0' is recommended. :::{note} The `meigwclrS` register does not have any physical storage elements associated with it. It is write-only and solely serves as the trigger to clear the interrupt pending (IP) bit of the configurable gateway S. ::: These 32-bit registers are idempotent memory-mapped control registers. :::{list-table} External Interrupt Gateway Clear Register *S=1..255* (meigwclrS, at PIC_base_addr+0x5000+S*4) :name: tab-external-interrupt-gateway-clear-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:0 - Reserved - R0/WA - 0 ::: ## PIC CSR Address Map {numref}`tab-pic-non-standard-risc-v-csr-address-map` summarizes the PIC non-standard RISC-V CSR address map. :::{list-table} PIC Non-standard RISC-V CSR Address Map :name: tab-pic-non-standard-risc-v-csr-address-map * - **Number** - **Privilege** - **Name** - **Description** - **Section** * - 0xBC8 - MRW - meivt - External interrupt vector table register - [](interrupts.md#external-interrupt-vector-table-register-meivt) * - 0xBC9 - MRW - meipt - External interrupt priority threshold register - [](interrupts.md#external-interrupt-priority-threshold-register-meipt) * - 0xBCA - MRW - meicpct - External interrupt claim ID / priority level capture trigger register - [External Interrupt Claim ID / Priority Level Capture Trigger Register (meicpct)](interrupts.md#external-interrupt-claim-id-priority-level-capture-trigger-register-meicpct) * - 0xBCB - MRW - meicidpl - External interrupt claim ID’s priority level register - [External Interrupt Claim ID’s Priority Level Register (meicidpl)](interrupts.md#external-interrupt-claim-id-s-priority-level-register-meicidpl) * - 0xBCC - MRW - meicurpl - External interrupt current priority level register - [](interrupts.md#external-interrupt-current-priority-level-register-meicurpl) * - 0xFC8 - MRO - meihap - External interrupt handler address pointer register - [](interrupts.md#external-interrupt-handler-address-pointer-register-meihap) ::: ## PIC Memory-Mapped Register Address Map {numref}`tab-pic-memory-mapped-register-address-map` summarizes the PIC memory-mapped register address map. :::{list-table} PIC Memory-mapped Register Address Map :name: tab-pic-memory-mapped-register-address-map * - **Address Offset from PIC_base_addr** - **Address Offset from PIC_base_addr** - - - * - **Start** - **End** - **Name** - **Description** - **Section** * - + 0x0000 - + 0x0003 - Reserved - Reserved - * - + 0x0004 - + 0x0004 + {math}`S_{max}`*4-1 - meiplS - External interrupt priority level register - [](interrupts.md#external-interrupt-priority-level-registers-meipls) * - + 0x0004 + {math}`S_{max}`*4 - + 0x0FFF - Reserved - Reserved - * - + 0x1000 - + 0x1000 + ({math}`X_{max}`+1)*4-1 - meipX - External interrupt pending register - [](interrupts.md#external-interrupt-pending-registers-meipx) * - + 0x1000 + ({math}`X_{max}`+1)*4 - + 0x1FFF - Reserved - Reserved - * - + 0x2000 - + 0x2003 - Reserved - Reserved - * - + 0x2004 - + 0x2004 + {math}`S_{max}`*4-1 - meieS - External interrupt enable register - [](interrupts.md#external-interrupt-enable-registers-meies) * - + 0x2004 + {math}`S_{max}`*4 - + 0x2FFF - Reserved - Reserved - * - + 0x3000 - + 0x3003 - mpiccfg - External interrupt PIC configuration register - [](interrupts.md#pic-configuration-register-mpiccfg) * - + 0x3004 - + 0x3FFF - Reserved - Reserved - * - + 0x4000 - + 0x4003 - Reserved - Reserved - * - + 0x4004 - + 0x4004 + {math}`S_{max}`*4-1 - meigwctrlS - External interrupt gateway configuration register (for configurable gateways only) - [](interrupts.md#external-interrupt-gateway-configuration-registers-meigwctrls) * - + 0x4004 + {math}`S_{max}`*4 - + 0x4FFF - Reserved - Reserved - * - + 0x5000 - + 0x5003 - Reserved - Reserved - * - + 0x5004 - + 0x5004 + {math}`S_{max}`*4-1 - meigwclrS - External interrupt gateway clear register (for configurable gateways only) - [](interrupts.md#external-interrupt-gateway-clear-registers-meigwclrs) * - + 0x5004 + {math}`S_{max}`*4 - + 0x7FFF - Reserved - Reserved - ::: :::{note} {math}`X_{max}` = ({math}`S_{max}` + 31) // 32, whereas // is an integer division ignoring the remainder ::: ## Interrupt Enable/Disable Code Samples ### Example Interrupt Flows * Macro flow to enable interrupt source id 5 with priority set to 7, threshold set to 1, and gateway configured for edge-triggered/active-low interrupt source: ```asm disable_ext_int // Disable interrupts (MIE[meip]=0) set_threshold 1 // Program global threshold to 1 init_gateway 5, 1, 1 // Configure gateway id=5 to edge-triggered/low clear_gateway 5 // Clear gateway id=5 set_priority 5, 7 // Set id=5 threshold at 7 enable_interrupt 5 // Enable id=5 enable_ext_int // Enable interrupts (MIE[meip]=1) ``` * Macro flow to initialize priority order: * To RISC-V standard order: ```asm init_priorityorder 0 // Set priority to standard RISC-V order init_nstthresholds 0 // Initialize nesting thresholds to 0 ``` * To reverse priority order: ```asm init_priorityorder 1 // Set priority to reverse order init_nstthresholds 15 // Initialize nesting thresholds to 15 ``` * Code to jump to the interrupt handler from the RISC-V trap vector: ```asm trap_vector: // Interrupt trap starts here when MTVEC[mode]=1 csrwi meicpct, 1 // Capture winning claim id and priority csrr t0, meihap // Load pointer index lw t1, 0(t0) // Load vector address jr t1 // Go there ``` * Code to handle the interrupt: ```asm eint_handler: : // Do some useful interrupt handling mret // Return from ISR ``` ### Example Interrupt Macros * Disable external interrupt: ```asm .macro disable_ext_int // Clear MIE[miep] disable_ext_int_\@: li a0, (1<<11) csrrc zero, mie, a0 .endm ``` * Enable external interrupt: ```asm .macro enable_ext_int enable_ext_int_\@: // Set MIE[miep] li a0, (1<<11) csrrs zero, mie, a0 .endm ``` * Initialize external interrupt priority order: ```asm .macro init_priorityorder priord init_priorityorder_\@: li tp, (RV_PIC_BASE_ADDR + RV_PIC_MPICCFG_OFFSET) li t0, \priord sw t0, 0(tp) .endm ``` * Initialize external interrupt nesting priority thresholds: ```asm .macro init_nstthresholds threshold init_nstthresholds_\@: li t0, \threshold li tp, (RV_PIC_BASE_ADDR + RV_PIC_MEICIDPL_OFFSET) sw t0, 0(tp) li tp, (RV_PIC_BASE_ADDR + RV_PIC_MEICURPL_OFFSET) sw t0, 0(tp) .endm ``` * Set external interrupt priority threshold: ```asm .macro set_threshold threshold set_threshold_\@: li tp, (RV_PIC_BASE_ADDR + RV_PIC_MEIPT_OFFSET) li t0, \threshold sw t0, 0(tp) .endm ``` * Enable interrupt for source *id*: ```asm .macro enable_interrupt id enable_interrupt_\@: li tp, (RV_PIC_BASE_ADDR + RV_PIC_MEIE_OFFSET + (\id <<2)) li t0, 1 sw t0, 0(tp) .endm ``` * Set priority of source *id*: ```asm .macro set_priority id, priority set_priority_\@: li tp, (RV_PIC_BASE_ADDR + RV_PIC_MEIPL_OFFSET + (\id <<2)) li t0, \priority sw t0, 0(tp) .endm ``` * Initialize gateway of source *id*: ```asm .macro init_gateway id, polarity, type init_gateway_\@: li tp, (RV_PIC_BASE_ADDR + RV_PIC_MEIGWCTRL_OFFSET + (\id <<2)) li t0, ((\type<<1) | \polarity) sw t0, 0(tp) .endm ``` * Clear gateway of source *id*: ```asm .macro clear_gateway id clear_gateway_\@: li tp, (RV_PIC_BASE_ADDR + RV_PIC_MEIGWCLR_OFFSET + (\id <<2)) sw zero, 0(tp) .endm ``` ================================================ FILE: docs/source/intro.md ================================================ # RISC-V VeeR EL2 Programmer's Reference Manual **Revision:** 2.0 January 14, 2025 ![CHIPS Alliance logo](img/logo.png) ![VeeR project logo](img/VeeR-logo-white-rgb.png) ``` SPDX-License-Identifier: Apache-2.0 Copyright © 2022 CHIPS Alliance. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ``` ## Document Revision History :::{list-table} Revision History :name: tab-revision-history :header-rows: 1 * - Revision - Date - Contents * - 1.0 - Jan 23, 2020 - Changes: - initial revision * - 1.1 - Mar 4, 2020 - Changes: - added note that mscause values are subject to change (section [](memory-map.md#machine-secondary-cause-register-mscause)) - added note that uninitialized DCCM may cause loads to get incorrect data (section []( error-protection.md#error-detection-and-handling)) - added Debug Module reset description (section [Debug Module Reset (dbg_rst_l)](clocks.md#debug-module-reset-dbg-rst-l)) - updated port list ({numref}`tab-core-complex-signals`): - added dbg_rst_l signal - added footnote clarifying trace port signals - fixed width of trace_rv_i_interrupt_ip bus - added 'Compliance Test Suite Failures' chapter [](tests.md) * - 1.2 - Mar 29, 2020 - Changes: - fixed note how writing illegal value to mrac register is handled by hardware in [](memory-map.md#region-access-control-register-mrac) - removed note that mscause values are subject to change in [](memory-map.md#machine-secondary-cause-register-mscause) - updated mscause values ({numref}`tab-machine-secondary-cause-register`) - added [Internal Timers chapter](timers.md) and references throughout document - incremented mimpid register value from '1' to '2' ({numref}`tab-veer-el2-core-specific-std-rv-machine-information-csrs`) * - 1.3 - Nov 16, 2020 - Changes: - updated versions of RISC-V Base ISA [[1]](ref-1) and Privileged [[2]](ref-2) and link to RISC-V Debug [[3]](ref-3) specifications (Reference Documents) - added RISC-V Bit-manipulation sub-extensions (Reference Documents, sections [](overview.md#features) and [](overview.md#standard-extensions), and {numref}`tab-list-of-countable-events`) - added footnote that misaligned accesses to side-effect regions trigger a misaligned exception instead of the recommended access fault exception ({numref}`tab-handling-misaligned-addresses`) - added note to mdseac register description clarifying captured address in [](memory-map.md#d-bus-first-error-address-capture-register-mdseac) - clarified that mscause value of '0' indicates no additional information available ([](memory-map.md#machine-secondary-cause-register-mscause)) - added description of SoC access expectation ([](memory-map.md#expected-soc-behavior-for-accesses)) - added note that NMIs are fatal ([](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector)) - added note that mitcnt0/1 register is not cleared if write to it coincides with internal timer interrupt ([Internal Timer Counter 0 / 1 Register (mitcnt0/1)](timers.md#internal-timer-counter-0-1-register-mitcnt0-1)) - clarified note that debug single-step action is delayed while MPC debug halted ([](power.md#power-states)) - added cross-references to debug CSR descriptions ({numref}`tab-core-activity-states`, {numref}`tab-veer-el2-multi-core-debug-ctrl-status-signals`, {numref}`tab-veer-el2-std-risc-v-csr-address-map`, and sections [](performance.md#count-impacting-conditions) and [](clocks.md#core-complex-reset-to-debug-mode)) - added note that debug single-stepping stays pending while MPC debug halted ([](power.md#single-stepping)) - removed note that PMU halt or run request may not be acknowledged if already in requested activity state ([](power.md#power-control-and-status-signals)) - amended debug_mode_status signal description ({numref}`tab-veer-el2-multi-core-debug-ctrl-status-signals`) - added note that mpc_debug_run_req is required to exit Debug Mode if entered after reset using mpc_reset_run_req ([](power.md#multi-core-debug-control-and-status-signals)) - added PIC I/O power reduction feature description (sections [](interrupts.md#features), [](interrupts.md#power-reduction), and [](interrupts.md#external-interrupt-pending-registers-meipx) and {numref}`tab-clock-gating-cr`) - added note that spurious interrupts may be captured for disabled external interrupts ([](interrupts.md#gateway)) - added note that edge-triggered interrupt lines must be tied off to inactive state ([](interrupts.md#gateway)) - fixed gateway initialization macro example ([](interrupts.md#example-interrupt-macros)) - added note that mtime and mtimecmp registers must be provided by SoC ([](performance.md#standard-risc-v-registers)) - changed value when writing unsupported event number to mhpmevent3-6 registers to '0' ([](performance.md#events)) - added note that index field does not have WARL behavior ({numref}`tab-cache-array-dicawics`) - added [Debug Support chapter](debugging.md) - added 'trace disable' bit to mfdc register ({numref}`tab-feature-disable-cr`) - clarified effect of sepd bit of mfdc register ({numref}`tab-feature-disable-cr`) - added note regarding physical design considerations for rst_l signal ([Core Complex Reset (rst_l)](clocks.md#core-complex-reset-rst-l)) - updated 'Reset to Debug-Mode' description ([](clocks.md#core-complex-reset-to-debug-mode)) - updated trace port interrupt/exception signaling to new optimized scheme ({numref}`tab-core-complex-signals`) - added erratum for abstract command register read capability ([](errata.md#debug-abstract-command-register-may-return-non-zero-value-on-read)) - incremented mimpid register value from '2' to '3' ({numref}`tab-veer-el2-core-specific-std-rv-machine-information-csrs`) * - 1.4 - Apr 19, 2022 - Changes: - updated version and link of RISC-V Bit-manipulation [[4]](ref-4) specification (Reference Documents) - updated list of sub-extension instructions to RISC-V Bitmanip Extension specification version 0.94-draft (1/20/21) ([](overview.md#standard-extensions)) - updated note regarding priority of simultaneous store and non-blocking load bus errors ([](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - fixed register name and added cross-reference (Footnote 20) - added footnote that load/store access crossing upper boundary of DCCM or PIC memory range report base address of access in mtval register (Footnote 22) - clarified that correctable error counter/threshold registers are always instantiated (sections [I-Cache Error Counter/Threshold Register (micect)](error-protection.md#i-cache-error-counter-threshold-register-micect), [Iccm Correctable Error Counter/Threshold Register (miccmect)](error-protection.md#iccm-correctable-error-counter-threshold-register-miccmect), and [Dccm Correctable Error Counter/Threshold Register (mdccmect)](error-protection.md#dccm-correctable-error-counter-threshold-register-mdccmect)) - corrected PIC I/O power reduction feature description ([](interrupts.md#power-reduction)) - incremented mimpid register value from '3' to '4' ({numref}`tab-veer-el2-core-specific-std-rv-machine-information-csrs`) * - 2.0 - Jan 14, 2025 - Changes: - Added description of PMP and ePMP functionalities - Added description of RISC-V User privilege level - Added information on verification, debugging and running Tock ::: ## Reference Documents :::{list-table} Reference Documents :name: tab-reference-documents :header-rows: 1 * - **Item #** - **Document** - **Revision Used** - **Comment** * - 1 - The RISC-V Instruction Set Manual Volume I: User-Level ISA - 20190608-Base-Ratified - Specification ratified * - 2 - The RISC-V Instruction Set Manual Volume II: Privileged Architecture - 20190608-Priv-MSU-Ratified - Specification ratified * - 2 (PLIC) - The RISC-V Instruction Set Manual Volume II: Privileged Architecture - 1.11-draft December 1, 2018 - Last specification version with PLIC chapter * - 3 - RISC-V External Debug Support - 0.13.2 - Specification ratified * - 4 - RISC-V Bitmanip Extension - 0.94-draft (January 20, 2021) - Zba, Zbb, Zbc, and Zbs subextensions are "frozen" * - 5 - The RISC-V Instruction Set Manual Volume II: Privileged Architecture - Document Version 20211203 - Specification ratified * - 6 - PMP Enhancements for memory access and execution prevention on Machine mode (Smepmp) - Version 1.0, 12/2021 - Specification ratified ::: ## Abbreviations :::{table} Abbreviations :name: tab-abbreviations :header-rows: 1 | Abbreviation | Description | |----------------|--------------------------------------------------------| | AHB | Advanced High-performance Bus (by ARM) | | AMBA | Advanced Microcontroller Bus Architecture (by ARM) | | ASIC | Application Specific Integrated Circuit | | AXI | Advanced eXtensible Interface (by ARM) | | CCM | Closely Coupled Memory (= TCM) | | CPU | Central Processing Unit | | CSR | Control and Status Register | | DCCM | Data Closely Coupled Memory (= DTCM) | | DEC | DECoder unit (part of core) | | DMA | Direct Memory Access | | DTCM | Data Tightly Coupled Memory (= DCCM) | | ECC | Error Correcting Code | | EXU | EXecution Unit (part of core) | | ICCM | Instruction Closely Coupled Memory (= ITCM) | | IFU | Instruction Fetch Unit | | ITCM | Instruction Tightly Coupled Memory (= ICCM) | | JTAG | Joint Test Action Group | | LSU | Load/Store Unit (part of core) | | MPC | Multi-Processor Controller | | MPU | Memory Protection Unit | | NMI | Non-Maskable Interrupt | | PIC | Programmable Interrupt Controller | | PLIC | Platform-Level Interrupt Controller | | POR | Power-On Reset | | RAM | Random Access Memory | | RAS | Return Address Stack | | ROM | Read-Only Memory | | SECDED | Single-bit Error Correction/Double-bit Error Detection | | SEDDED | Single-bit Error Detection/Double-bit Error Detection | | SoC | System on Chip | | TBD | To Be Determined | | TCM | Tightly Coupled Memory (= CCM) | ::: ================================================ FILE: docs/source/memory-map.md ================================================ # Memory Map This chapter describes the memory map as well as the various memories and their properties of the VeeR EL2 core. ## Address Regions The 32-bit address space is subdivided into sixteen fixed-sized, contiguous 256MB regions. Each region has a set of access control bits associated with it ([](memory-map.md#region-access-control-register-mrac)). ## Access Properties Each region has two access properties which can be independently controlled. They are: * **Cacheable:** Indicates if this region is allowed to be cached or not. * **Side effect:** Indicates if read/write accesses to this region may have side effects (i.e., non-idempotent accesses which may potentially have side effects on any read/write access; typical for I/O, speculative or redundant accesses must be avoided) or have no side effects (i.e., idempotent accesses which have no side effects even if the same access is performed multiple times; typical for memory). Note that stores with potential side effects (i.e., to non-idempotent addresses) cannot be combined with other stores in the core's unified read/write buffer. ## Memory Types There are two different classes of memory types mapped into the core's 32-bit address range, core local and system bus attached. ### Core Local #### ICCM and DCCM Two dedicated memories, one for instruction and the other for data, are tightly coupled to the core. These memories provide low-latency access and SECDED ECC protection. Their respective sizes (4, 8, 16, 32, 48 [^fn-iccm-dccm-1], 64, 128, 256, or 512KB) are set as arguments at build time of the core. [^fn-iccm-dccm-1]: DCCM only #### Local Memory-Mapped Control/Status Registers To provide control for regular operation, the core requires a number of memory-mapped control/status registers. For example, some external interrupt functions are controlled and serviced with accesses to various registers while the system is running. ### Accessed via System Bus #### System ROMs The SoC may host ROMs which are mapped to the core's memory address range and accessed via the system bus. Both instruction and data accesses are supported to system ROMs. #### System SRAMs The SoC hosts a variety of SRAMs which are mapped to the core's memory address range and accessed via the system bus. #### System Memory-Mapped I/O The SoC hosts a variety of I/O device interfaces which are mapped to the core's memory address range and accessed via the system bus. ### Mapping Restrictions Core-local memories and system bus-attached memories must be mapped to different regions. Mapping both classes of memory types to the same region is not allowed. Furthermore, it is recommended that all core-local memories are mapped to the same region. ## Memory Type Access Properties {numref}`tab-access-properites-memory-type` specifies the access properties of each memory type. During system boot, firmware must initialize the properties of each region based on the memory type present in that region. :::{note} Some memory-mapped I/O and control/status registers may have no side effects (i.e., are idempotent), but characterizing all these registers as having potentially side effects (i.e., are non-idempotent) is safe. ::: :::{list-table} Access Properties for each Memory Type :name: tab-access-properites-memory-type :header-rows: 1 * - **Region** - **Memory Type** - **Cacheable** - **Side Effect** * - **Core Local** - ICCM - No - No * - Core Local - DCCM - No - No * - Core Local - Memory-mapped control/status registers - No - Yes * - Accessed via System Bus - ROMs - Yes - No * - Accessed via System Bus - SRAMs - Yes - No * - Accessed via System Bus - I/Os - No - Yes * - Accessed via System Bus - Memory-mapped control/status registers - No - Yes ::: :::{note} 'Cacheable = Yes' and 'Side Effect = Yes' is an illegal combination. ::: ## Memory Access Ordering Loads and stores to system bus-attached memory (i.e. accesses with no side effects, idempotent) and devices (i.e. accesses with potential side effects, non-idempotent) pass through a unified read/write buffer. The buffer is implemented as a FIFO. ### Load-To-Load and Store-To-Store Ordering All loads are sent to the system bus interface in program order. Also, all stores are sent to the system bus interface in program order. ### Load/Store Ordering #### Accesses with Potential Side Effects (i.e., Non-Idempotent) When a load with potential side effects (i.e., non-idempotent) enters the buffer, the entire unified buffer is emptied, i.e., both stores with no side effects (i.e., idempotent) and with potential side effects (i.e., non-idempotent) are drained out. Loads with potential side effects (i.e., non-idempotent) are sent out to the system bus with their exact size. Stores with potential side effects (i.e., non-idempotent) are neither coalesced nor forwarded to a load. #### Accesses with No Side Effects (i.e., Idempotent) Loads with no side effects (i.e., idempotent) are always issued as double-words and check the contents of the unified buffer: 1. **Full address match** (all load bytes present in the unified buffer): Data is forwarded from the unified buffer. The load does not go out to the system bus. 2. **Partial address match** (some of the load bytes are in the unified buffer): The entire unified buffer is emptied, then the load request goes to the system bus. 3. **No match** (none of the bytes are in the unified buffer): The load is presented to the system bus interface without waiting for the stores to drain. #### Ordering of Store - Load with No Side Effects (i.e., Idempotent) A `fence` instruction is required to order an older store before a younger load with no side effects (i.e., idempotent). :::{note} All memory-mapped register writes must be followed by a `fence` instruction to enforce ordering and synchronization. ::: ### Fencing #### Instructions The `fence.i` instruction operates on the instruction memory and/or I-cache. This instruction causes a flush, a flash invalidation of the I-cache, and a refetch of the next program counter (RFNPC). The refetch is guaranteed to miss the I-cache. Note that since the `fence.i` instruction is used to synchronize the instruction and data streams, it also includes the functionality of the `fence` instruction (see [](memory-map.md#data)). #### Data The `fence` instruction is implemented conservatively in VeeR EL2 to keep the implementation simple. It always performs the most conservative fencing, independent of the instruction's arguments. The `fence` instruction is presynced to make sure that there are no instructions in the LSU pipe. It stalls until the LSU indicates that the store buffer and unified buffer have been fully drained (i.e., are empty). The `fence` instruction is only committed after all LSU buffers are idle and all outstanding bus transactions are completed. ### Imprecise Data Bus Errors All store errors as well as non-blocking load errors on the system bus are imprecise. The address of the first occurring imprecise data system bus error is logged and a non-maskable interrupt (NMI) is flagged for the first reported error only. For stores, if there are other stores in the unified buffer behind the store which had the error, these stores are sent out on the system bus and any error responses are ignored. Similarly, for non-blocking loads, any error responses on subsequent loads sent out on the system bus are ignored. NMIs are fatal, architectural state is lost, and the core needs to be reset. The reset also unlocks the first error address capture register again. :::{note} It is possible to unlock the first error address capture register with a write to an unlock register as well (see [](memory-map.md#d-bus-error-address-unlock-register-mdeau) for more details), but this may result in unexpected behavior. ::: ## Memory Protection To eliminate issuing speculative accesses to the IFU and LSU bus interfaces, VeeR EL2 provides a rudimentary memory protection mechanism for instruction and data accesses outside of the ICCM and DCCM memory regions. Separate core build arguments for instructions and data are provided by the Memory Protection Unit (MPU) to enable and configure up to 8 address windows each. An instruction fetch to a non-ICCM region must fall within the address range of at least one instruction access window for the access to be forwarded to the IFU bus interface. If at least one instruction access window is enabled, nonspeculative fetch requests which are not within the address range of any enabled instruction access window cause a precise instruction access fault exception. If none of the 8 instruction access windows is enabled, the memory protection mechanism for instruction accesses is turned off. For the ICCM region, accesses within the ICCM's address range are allowed. However, any access not within the ICCM's address range results in a precise instruction access fault exception. Similarly, a load/store access to a non-DCCM or non-PIC memory-mapped control register region must fall within the address range of at least one data access window for the access to be forwarded to the LSU bus interface. If at least one data access window is enabled, non-speculative load/store requests which are not within the address range of any enabled data access window cause a precise load/store address misaligned or access fault exception. If none of the 8 data access windows is enabled, the memory protection mechanism for data accesses is turned off. For the DCCM and PIC memory-mapped control register region(s), accesses within the DCCM's or the PIC memory-mapped control register's address range are allowed. However, any access not within the DCCM's or PIC memory-mapped control register's address range results in a precise load/store address misaligned or access fault exception. The configuration parameters for each of the 8 instruction and 8 data access windows are: * Enable/disable instruction/data access window 0..7, * a base address of the window (which must be 64B-aligned), and * a mask specifying the size of the window (which must be an integer-multiple of 64 bytes minus 1). See [](build-args.md#memory-protection-build-arguments) for more information. ## Exception Handling Capturing the faulting effective address causing an exception helps assist firmware in handling the exception and/or provides additional information for firmware debugging. For precise exceptions, the faulting effective address is captured in the standard RISC-V `mtval` register (see Section 3.1.17 in [[2]](intro.md#ref-2)). For imprecise exceptions, the address of the first occurrence of the error is captured in a platform-specific error address capture register (see [](memory-map.md#d-bus-first-error-address-capture-register-mdseac)). ### Imprecise Bus Error Non-Maskable Interrupt Store bus errors are fatal and cause a non-maskable interrupt (NMI). The store bus error NMI has an `mcause` value of 0xF000_0000. Likewise, non-blocking load bus errors are fatal and cause a non-maskable interrupt (NMI). The non-blocking load bus error NMI has an `mcause` value of 0xF000_0001. :::{note} The address of the first store or non-blocking load error on the D-bus is captured in the `mdseac` register (see [](memory-map.md#d-bus-first-error-address-capture-register-mdseac)). The register is unlocked either by resetting the core after the NMI has been handled or by a write to the `mdeau` register (see [](memory-map.md#d-bus-error-address-unlock-register-mdeau)). While the `mdseac` register is locked, subsequent D-bus errors are gated (i.e., they do not cause another NMI), but NMI requests originating external to the core are still honored. ::: :::{note} The AXI4 bus is able to report a load bus error and a store bus error simultaneously. If store and non-blocking load bus errors are reported in the same clock cycle, the store bus error has higher priority. ::: ### Correctable Error Local Interrupt I-cache parity/ECC errors, ICCM correctable ECC errors, and DCCM correctable ECC errors are counted in separate correctable error counters (see sections [I-Cache Error Counter/Threshold Register (micect)](error-protection.md#i-cache-error-counter-threshold-register-micect), [Iccm Correctable Error Counter/Threshold Register (miccmect)](error-protection.md#iccm-correctable-error-counter-threshold-register-miccmect), and [Dccm Correctable Error Counter/Threshold Register (mdccmect)](error-protection.md#dccm-correctable-error-counter-threshold-register-mdccmect), respectively). Each counter also has its separate programmable error threshold. If any of these counters has reached its threshold, a correctable error local interrupt is signaled. Firmware should determine which of the counters has reached the threshold and reset that counter. A local-to-the-core interrupt for correctable errors has pending (*mceip*) and enable (*mceie*) bits in bit position 30 of the standard RISC-V `mip` (see {numref}`tab-machine-interrupt-pending-register`) and `mie` (see {numref}`tab-machine-interrupt-enable-register`) registers, respectively. The priority is lower than the RISC-V External interrupt, but higher than the RISC-V Software and Timer interrupts, (see {numref}`tab-veer-el2-platform-specific-and-std-risc-v-interrupt-priorities`). The correctable error local interrupt has an `mcause` value of 0x8000_001E (see {numref}`tab-machine-cause-register`). ### Rules for Core-Local Memory Accesses The rules for instruction fetch and load/store accesses to core-local memories are: 1. An instruction fetch access to a region 1. containing one or more ICCM sub-region(s)causes an exception if 1. the access is not completely within the ICCM sub-region, or 1. the boundary of an ICCM to a non-ICCM sub-region and vice versa is crossed, even if the region contains a DCCM/PIC memory-mapped control register sub-region. 1. not containing an ICCM sub-region goes out to the system bus, even if the region contains a DCCM/PIC memory-mapped control register sub-region. 1. A load/store access to a region 1. containing one or more DCCM/PIC memory-mapped control register sub-region(s) causes an exception if 1. the access is not completely within the DCCM/PIC memory-mapped control register subregion, or 1. the boundary of 1. a DCCM to a non-DCCM sub-region and vice versa, or 1. a PIC memory-mapped control register sub-region is crossed, even if the region contains an ICCM sub-region. 1. not containing a DCCM/PIC memory-mapped control register sub-region goes out to the system bus, even if the region contains an ICCM sub-region. ### Core-Local / D-Bus Access Prediction In VeeR EL2, a prediction is made early in the pipeline if the access is to a core-local address (i.e., DCCM or PIC memory-mapped register) or to the D-bus (i.e., a memory or register address of the SoC). The prediction is based on the base address (i.e., value of register *rs1*) of the load/store instruction. Later in the pipeline, the actual address is calculated also taking the offset into account (i.e., value of register *rs1 + offset*). A mismatch of the predicted and the actual destination (i.e., a core-local or a D-bus access) results in a load/store access fault exception. ### Unmapped Addresses :::{list-table} Handling of Unmapped Addresses :name: tab-handling-unmapped-addresses :header-rows: 1 * - **Access** - **Core/Bus** - **Side Effect** - **Action** - **Comments** * - Fetch - Core - N/A - Instruction access fault exception [^fn-unmapped-address-1], [^fn-unmapped-address-2] - Precise exception (e.g., address out-of-range) * - Fetch - Bus - N/A - Instruction access fault exception [^fn-unmapped-address-1] - Precise exception (e.g., address out-of-range) * - Load - Core - No - Load access fault exception [^fn-unmapped-address-3], [^fn-unmapped-address-4] - Precise exception (e.g., address out-of-range) * - Load - Bus - No - non-blocking load bus error nmi (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - - imprecise, fatal - capture load address in core bus interface * - Load - Bus - Yes - non-blocking load bus error nmi (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - - imprecise, fatal - capture load address in core bus interface * - Store - Core - No - Store/AMO [^fn-unmapped-address-5] access fault exception [^fn-unmapped-address-3], [^fn-unmapped-address-4] - Precise exception * - Store - Bus - No - Store bus error NMI (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - - Imprecise, fatal - Capture store address in core bus interface * - Store - Bus - Yes - Store bus error NMI (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - - Imprecise, fatal - Capture store address in core bus interface * - DMA Read / DMA Write - Bus - N/A - DMA slave bus error - Send error response to master ::: :::{note} It is recommended to provide address gaps between different memories to ensure unmapped address ::: [^fn-unmapped-address-1]: If any byte of an instruction is from an unmapped address, an instruction access fault precise exception is flagged. [^fn-unmapped-address-2]: Exception also flagged for fetches to the DCCM address range if located in the same region, or if located in different regions and no SoC address is a match. [^fn-unmapped-address-3]: Exception also flagged for PIC load/store not word-sized or address not word-aligned. [^fn-unmapped-address-4]: Exception also flagged for loads/stores to the ICCM address range if located in the same region, or if located in different regions and no SoC address is a match. [^fn-unmapped-address-5]: AMO refers to the RISC-V "A" (atomics) extension, which is not implemented in VeeR EL2. ### Misaligned Accesses General notes: * The core performs a misalignment check during the address calculation. * Accesses across region boundaries always cause a misaligned exception. * Splitting a load/store from/to an address with no side effects (i.e., idempotent) is not of concern for VeeR EL2. :::{list-table} Handling of Misaligned Accesses :name: tab-handling-misaligned-addresses :header-rows: 1 * - **Access** - **Core/Bus** - **Side Effect** - **Region Cross** - **Action** - **Comments** * - Fetch - Core - N/A - No - N/A - Not possible [^fn-misaligned-accesses-1] * - Fetch - Bus - N/A - No - N/A - Not possible [^fn-misaligned-accesses-1] * - Load - Core - No - No - Load split into multiple DCCM read accesses - Split performed by core * - Load - Bus - No - No - Load split into multiple bus transactions - Split performed by core * - Load - Bus - Yes [^fn-misaligned-accesses-2] - No - Load address misaligned exception - Precise exception * - Store - Core - No - No - Store split into multiple DCCM write accesses - Split performed by core * - Store - Bus - No - No - Store split into multiple bus transactions - Split performed by core * - Store - Bus - Yes [^fn-misaligned-accesses-2] - No - Store/AMO address misaligned exception - Precise exception * - Fetch - N/A - N/A - Yes - N/A - Not possible [^fn-misaligned-accesses-1] * - Load - N/A - N/A - Yes - Load address misaligned exception - Precise exception * - Store - N/A - N/A - Yes - Store/AMO address misaligned exception - Precise exception * - DMA Read - Bus - N/A - N/A - DMA slave bus error - Send error response to master * - DMA Write [^fn-misaligned-accesses-3] - Bus - N/A - N/A - DMA slave bus error - Send error response to master ::: [^fn-misaligned-accesses-1]: Accesses to the I-cache or ICCM initiated by fetches never cross 16B boundaries. I-cache fills are always aligned to 64B. Misaligned accesses are therefore not possible. [^fn-misaligned-accesses-2]: The RISC-V Privileged specification recommends that misaligned accesses to regions with potential side-effects should trigger an access fault exception, instead of a misaligned exception (see Section 3.5.6 in [[2]](intro.md#ref-2)). Note that VeeR EL2 triggers a misaligned exception in this case. To avoid potential side-effects, the exception handler should not emulate a misaligned access using multiple smaller aligned accesses. [^fn-misaligned-accesses-3]: This case is in violation with the write alignment rules specified in section [](memory-map.md#write-alignment-rules). ### Uncorrectable Ecc Errors :::{list-table} Handling of Uncorrectable ECC Errors :name: tab-handling-uncorrectable-ecc-errors :header-rows: 1 * - **Access** - **Core/Bus** - **Side Effect** - **Action** - **Comments** * - Fetch - Core - N/A - Instruction access fault exception - Precise exception (i.e., for oldest instruction in pipeline only) * - Fetch - Bus - N/A - Instruction access fault exception - Precise exception (i.e., for oldest instruction in pipeline only) * - Load - Core - No - Load access fault exception - Precise exception (i.e., for non-speculative load only) * - Load - Core - Yes - Load access fault exception - Precise exception (i.e., for non-speculative load only) * - Load - Bus - No - Non-blocking load bus error NMI (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - - Imprecise, fatal - Capture load address in core bus interface * - Load - Bus - Yes - Non-blocking load bus error NMI (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - - Imprecise, fatal - Capture load address in core bus interface * - Store - Core - No - Store/AMO access fault exception - Precise exception (i.e., for non-speculative store only) * - Store - Core - Yes - Store/AMO access fault exception - Precise exception (i.e., for non-speculative store only) * - Store - Bus - No - Store bus error NMI (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - - Imprecise, fatal - Capture store address in core bus interface * - Store - Bus - Yes - Store bus error NMI (see [](memory-map.md#imprecise-bus-error-non-maskable-interrupt)) - - Imprecise, fatal - Capture store address in core bus interface * - DMA Read - Bus - N/A - DMA slave bus error - Send error response to master ::: :::{note} DMA write accesses to the ICCM or DCCM always overwrite entire 32-bit words and their corresponding ECC bits. Therefore, ECC bits are never checked and errors not detected on DMA writes. ::: ### Correctable Ecc/Parity Errors :::{list-table} Handling of Correctable ECC/Parity Errors Access Core/Bus Side Effect Action :name: tab-handling-correctable-ecc-errors :header-rows: 1 * - **Access** - **Core/Bus** - **Side Effect** - **Action** - **Comments** * - Fetch - Core - N/A - For I-cache accesses: - Increment correctable I-cache error counter in core - If I-cache error threshold reached, signal correctable error local interrupt (see [I-Cache Error Counter/Threshold Register (micect)](error-protection.md#i-cache-error-counter-threshold-register-micect)) - Invalidate all cache lines of set - Perform RFPC flush - Flush core pipeline - Refetch cache line from SoC memory - - For all fetches from I-cache (i.e., out of pipeline, independent of actual instruction execution) - For I-cache with tag/instruction ECC protection, single- and double-bit errors are recoverable * - Fetch - Core - N/A - For ICCM accesses: - Increment correctable ICCM error counter in core - If ICCM error threshold reached, signal correctable error local interrupt (see [Iccm Correctable Error Counter/Threshold Register (miccmect)](error-protection.md#iccm-correctable-error-counter-threshold-register-miccmect)) - Perform RFPC flush - Flush core pipeline - Write corrected data back to ICCM - Refetch instruction(s) from ICCM - - For all fetches from ICCM (i.e., out of pipeline, independent of actual instruction execution) - ICCM errors trigger an RFPC (ReFetch PC) flush since in-line correction would require an additional cycle * - Fetch - Bus - N/A - - Increment correctable error counter in SoC - If error threshold reached, signal external interrupt - Write corrected data back to SoC memory - Errors in SoC memories are corrected at memory boundary and autonomously written back to memory array * - Load - Core - No - - Increment correctable DCCM error counter in core - If DCCM error threshold reached, signal correctable error local interrupt (see [Dccm Correctable Error Counter/Threshold Register (mdccmect)](error-protection.md#dccm-correctable-error-counter-threshold-register-mdccmect)) - Write corrected data back to DCCM - - For non-speculative accesses only - DCCM errors are in-line corrected and written back to DCCM * - Load - Core - Yes - - Increment correctable DCCM error counter in core - If DCCM error threshold reached, signal correctable error local interrupt (see [Dccm Correctable Error Counter/Threshold Register (mdccmect)](error-protection.md#dccm-correctable-error-counter-threshold-register-mdccmect)) - Write corrected data back to DCCM - - For non-speculative accesses only - DCCM errors are in-line corrected and written back to DCCM * - Load - Bus - No - - Increment correctable error counter in SoC - If error threshold reached, signal external interrupt - Write corrected data back to SoC memory - Errors in SoC memories are corrected at memory boundary and autonomously written back to memory array * - Load - Bus - Yes - - Increment correctable error counter in SoC - If error threshold reached, signal external interrupt - Write corrected data back to SoC memory - Errors in SoC memories are corrected at memory boundary and autonomously written back to memory array * - Store - Core - No - - Increment correctable dccm error counter in core - If dccm error threshold reached, signal correctable error local interrupt (see [Dccm Correctable Error Counter/Threshold Register (mdccmect)](error-protection.md#dccm-correctable-error-counter-threshold-register-mdccmect)) - Write corrected data back to dccm - - For non-speculative accesses only - Dccm errors are in-line corrected and written back to dccm * - Store - Core - Yes - - Increment correctable dccm error counter in core - If dccm error threshold reached, signal correctable error local interrupt (see [Dccm Correctable Error Counter/Threshold Register (mdccmect)](error-protection.md#dccm-correctable-error-counter-threshold-register-mdccmect)) - Write corrected data back to dccm - - For non-speculative accesses only - Dccm errors are in-line corrected and written back to dccm * - Store - Bus - No - - Increment correctable error counter in SoC - If error threshold reached, signal external interrupt - Write corrected data back to SoC memory - Errors in SoC memories are corrected at memory boundary and autonomously written back to memory array * - Store - Bus - Yes - - Increment correctable error counter in SoC - If error threshold reached, signal external interrupt - Write corrected data back to SoC memory - Errors in SoC memories are corrected at memory boundary and autonomously written back to memory array * - DMA Read - Bus - N/A - For ICCM accesses: - Increment correctable ICCM error counter in core - If ICCM error threshold reached, signal correctable error local interrupt (see [Iccm Correctable Error Counter/Threshold Register (miccmect)](error-protection.md#iccm-correctable-error-counter-threshold-register-miccmect)) - Write corrected data back to ICCM - DMA read access errors to ICCM are in-line corrected and written back to ICCM * - DMA Read - Bus - N/A - For DCCM accesses: - Increment correctable DCCM error counter in core - If DCCM error threshold reached, signal correctable error local interrupt (see [Dccm Correctable Error Counter/Threshold Register (mdccmect)](error-protection.md#dccm-correctable-error-counter-threshold-register-mdccmect)) - Write corrected data back to DCCM - DMA read access errors to DCCM are in-line corrected and written back to DCCM ::: :::{note} Counted errors could be from different, unknown memory locations. ::: :::{note} DMA write accesses to the ICCM or DCCM always overwrite entire 32-bit words and their corresponding ECC bits. Therefore, ECC bits are never checked and errors not detected on DMA writes. ::: ## Control/Status Registers A summary of platform-specific control/status registers in CSR space: * [](memory-map.md#region-access-control-register-mrac) * [](memory-map.md#memory-synchronization-trigger-register-dmst) * [](memory-map.md#d-bus-first-error-address-capture-register-mdseac) * [](memory-map.md#d-bus-error-address-unlock-register-mdeau) * [](memory-map.md#machine-secondary-cause-register-mscause) All reserved and unused bits in these control/status registers must be hardwired to '0'. Unless otherwise noted, all read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. ### Region Access Control Register (mrac) A single region access control register is sufficient to provide independent control for 16 address regions. :::{note} To guarantee that updates to the `mrac` register are in effect, if a region being updated is in the load/store space, a `fence` instruction is required. Likewise, if a region being updated is in the instruction space, a `fence.i` instruction (which flushes the I-cache) is required. ::: :::{note} The *sideeffect* access control bits are ignored by the core for load/store accesses to addresses mapped to core-local memories (i.e., DCCM and ICCM) and PIC memory-mapped control registers as well as for all instruction fetch accesses. The *cacheable* access control bits are ignored for instruction fetch accesses from addresses mapped to the ICCM, but not for any other addresses. ::: :::{note} The combination '11' (i.e., side effect and cacheable) is illegal. Writing '11' is mapped by hardware to the legal value '10' (i.e., side effect and non-cacheable). ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} Region Access Control Register (mrac, at CSR 0x7C0) :name: tab-region-access-control-register :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Y = 0..15 (= Region) - - - - * - sideeffectY - Y*2+1 - Side effect indication for region Y: - 0: No side effects (idempotent) - 1: Side effects possible (non-idempotent) - R/W - 0 * - cacheableY - Y*2 - Caching control for region Y: - 0: Caching not allowed - 1: Caching allowed - R/W - 0 ::: ### Memory Synchronization Trigger Register (dmst) The `dmst` register provides triggers to force the synchronization of memory accesses. Specifically, it allows a debugger to initiate operations that are equivalent to the `fence.i` (see [](memory-map.md#instructions)) and `fence` (see [](memory-map.md#data)) instructions. :::{note} This register is accessible in **Debug Mode only**. Attempting to access this register in machine mode raises an illegal instruction exception. ::: The *fence_i* and *fence* fields of the `dmst` register have W1R0 (Write 1, Read 0) behavior, as also indicated in the 'Access' column. This register is mapped to the non-standard read/write CSR address space. :::{list-table} Memory Synchronization Trigger Register (dmst, at CSR 0x7C4) :name: tab-memory-synchronization-trigger-register :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:2 - Reserved - R - 0 * - fence - 1 - Trigger operation equivalent to `fence` instruction - R0/W1 - 0 * - fence_i - 0 - Trigger operation equivalent to `fence.i` instruction - R0/W1 - 0 ::: ### D-Bus First Error Address Capture Register (mdseac) The address of the first occurrence of a store or non-blocking load error on the D-bus is captured in the `mdseac` register. Latching the address also locks the register. While the `mdseac` register is locked, subsequent D-bus errors are gated (i.e., they do not cause another NMI), but NMI requests originating external to the core are still honored. The `mdseac` register is unlocked by either a core reset (which is the safer option) or by writing to the `mdeau` register (see [](memory-map.md#d-bus-error-address-unlock-register-mdeau)). :::{note} The address captured in this register is the target (i.e., base) address of the store or non-blocking load which experienced an error. ::: :::{note} The NMI handler may use the value stored in the `mcause` register to differentiate between a D-bus store error, a D-bus non-blocking load error, and a core-external event triggering an NMI. ::: :::{note} Capturing an address of a store or non-blocking load D-bus error in the `mdseac` register is independent of the actual taking of an NMI due to the bus error. For example, if a request on the NMI pin arrives just prior to the detection of a store or non-blocking load error on the D-bus, the address of the bus error may still be logged in the `mdseac` register. ::: This register is mapped to the non-standard read-only CSR address space. :::{list-table} D-Bus First Error Address Capture Register (mdseac, at CSR 0xFC0) :name: tab-d-bus-first-error-address-capture-register :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - erraddr - 31:0 - Address of first occurrence of D-bus store or non-blocking load error - R - 0 ::: ### D-Bus Error Address Unlock Register (mdeau) Writing to the `mdeau` register unlocks the `mdseac` register (see [](memory-map.md#d-bus-first-error-address-capture-register-mdseac)) after a D-bus error address has been captured. This write access also reenables the signaling of an NMI for a subsequent D-bus error. :::{note} Nested NMIs might destroy core state and, therefore, receiving an NMI should still be considered fatal. Issuing a core reset is a safer option to deal with a D-bus error. ::: The `mdeau` register has WAR0 (Write Any value, Read 0) behavior. Writing '0' is recommended. This register is mapped to the non-standard read/write CSR address space. :::{list-table} D-Bus Error Address Unlock Register (mdeau, at CSR 0xBC0) :name: tab-d-bus-error-address-unlock-register :header-rows: 1 * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - erraddr - 31:0 - Address of first occurrence of D-bus store or non-blocking load error - R - 0 ::: ### Machine Secondary Cause Register (mscause) The `mscause` register, in conjunction with the standard RISC-V `mcause` register (see [](adaptations.md#machine-cause-register-mcause)), allows the determination of the exact cause of a trap for cases where multiple, different conditions share a single trap code. The standard RISC-V mcause register provides the trap code and the `mscause` register provides supporting information about the trap to disambiguate different sources. A value of '0' indicates that there is no additional information available. {numref}`tab-machine-secondary-cause-register` lists VeeR EL2's standard exceptions/interrupts (regular text), platform-specific local interrupts (italic text), and NMI causes (bold text). The `mscause` register has WLRL (Write Legal value, Read Legal value) behavior. :::{note} VeeR EL2 implements only the 4 least-significant bits of the mscause register (i.e., `mscause[3:0]`). Writes to all higher bits are ignored, reads return 0 for those bits. ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} Machine Secondary Cause Register (mscause, at CSR 0x7FF) :name: tab-machine-secondary-cause-register :header-rows: 1 * - **mcause** - **mcause Description** - **mscause (Rel. Priority)** [^fn-mscause-register-1] - **mscause Description** - **Section(s)** * - **Exceptions** - - - - * - 0x1 - Instruction access fault - 0x9 (2) - I-side fetch precise bus error - [](memory-map.md#unmapped-addresses) and [](error-protection.md#error-detection-and-handling) * - 0x1 - Instruction access fault - 0x1 (3) - I-side ICCM double-bit ECC error - [](memory-map.md#uncorrectable-ecc-errors) and [](error-protection.md#error-detection-and-handling) * - 0x1 - Instruction access fault - 0x2 (0) - I-side core-local [^fn-mscause-register-2] unmapped address error - [](memory-map.md#unmapped-addresses) and [](error-protection.md#error-detection-and-handling) * - 0x1 - Instruction access fault - 0x3 (1) - I-side access out of MPU range - [](memory-map.md#memory-protection) * - 0x2 - Illegal instruction - 0x0 - None - N/A * - 0x3 - Breakpoint - 0x2 - ebreak (not to Debug Mode) - N/A * - 0x3 - Breakpoint - 0x1 - Trigger hit [^fn-mscause-register-3] (not to Debug Mode) - N/A * - 0x4 - Load address misaligned - 0x2 (0) - D-side load across region boundary - [](memory-map.md#misaligned-accesses) * - 0x4 - Load address misaligned - 0x1 (1) - D-side size-misaligned load to non-idempotent address - [](memory-map.md#misaligned-accesses) * - 0x5 - Load access fault - 0x2 (0) - D-side core-local [^fn-mscause-register-4], [^fn-mscause-register-5] load unmapped address error - [](memory-map.md#unmapped-addresses) and [](error-protection.md#error-detection-and-handling) * - 0x5 - Load access fault - 0x1 (4) - D-side DCCM load double-bit ECC error - [](memory-map.md#uncorrectable-ecc-errors) and [](error-protection.md#error-detection-and-handling) * - 0x5 - Load access fault - 0x3 (1) - D-side load access out of MPU range - [](memory-map.md#memory-protection) * - 0x5 - Load access fault - 0x5 (2) - D-side load region prediction error - [Core-Local / D-Bus Access Prediction](memory-map.md#core-local-d-bus-access-prediction) * - 0x5 - Load access fault - 0x6 (3) - D-side PIC [^fn-mscause-register-6] load access error - [](memory-map.md#unmapped-addresses) * - 0x6 - Store/AMO address misaligned - 0x2 (0) - D-side store across region boundary - [](memory-map.md#misaligned-accesses) * - 0x6 - Store/AMO address misaligned - 0x1 (1) - D-side size-misaligned store to non-idempotent address - [](memory-map.md#misaligned-accesses) * - 0x7 - Store/AMO access fault - 0x2 (0) - D-side core-local [^fn-mscause-register-4], [^fn-mscause-register-5] store unmapped address error - [](memory-map.md#unmapped-addresses) and [](error-protection.md#error-detection-and-handling) * - 0x7 - Store/AMO access fault - 0x1 (4) - D-side DCCM store double- bit ECC error - [](memory-map.md#uncorrectable-ecc-errors) and [](error-protection.md#error-detection-and-handling) * - 0x7 - Store/AMO access fault - 0x3 (1) - D-side store access out of MPU range - [](memory-map.md#memory-protection) * - 0x7 - Store/AMO access fault - 0x5 (2) - D-side store region prediction error - [Core-Local / D-Bus Access Prediction](memory-map.md#core-local-d-bus-access-prediction) * - 0x7 - Store/AMO access fault - 0x6 (3) - D-side PIC [^fn-mscause-register-6] store access error - [](memory-map.md#unmapped-addresses) * - 0xB - Environment call from M- mode - 0x0 - None - N/A * - **Interrupts** - - - - * - 0x8000_0003 - Machine software interrupt - 0x0 - Machine software - [](memory-map.md#software-interrupts) * - 0x8000_0007 - Machine timer [^fn-mscause-register-7] interrupt - 0x0 - Machine timer - N/A * - 0x8000_000B - Machine external interrupt - 0x0 - External interrupt - [](interrupts.md) * - *0x8000_001C* - *Machine internal timer 1 local interrupt* - 0x0 - *Internal timer 1 local interrupt* - [](timers.md#internal-timer-local-interrupts) * - *0x8000_001D* - *Machine internal timer 0 local interrupt* - 0x0 - *Internal timer 0 local interrupt* - [](timers.md#internal-timer-local-interrupts) * - *0x8000_001E* - *Machine correctable error local interrupt* - 0x0 - *Correctable error local interrupt* - [](memory-map.md#correctable-error-local-interrupt) * - **0x0000_0000** - **NMI** - **0x0** - **NMI pin assertion** - [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - **0xF000_0000** - **NMI** - **0x0** - **D-bus store error** - [](memory-map.md#imprecise-bus-error-non-maskable-interrupt) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - **0xF000_0001** - **NMI** - **0x0** - **D-bus non-blocking load error** - [](memory-map.md#imprecise-bus-error-non-maskable-interrupt) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - **0xF000_1000** - **NMI** - **0x0** - **Fast Interrupt double-bit ECC error** - [](interrupts.md#fast-interrupt-redirect) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - **0xF000_1001** - **NMI** - **0x0** - **Fast Interrupt DCCM region access error** - [](interrupts.md#fast-interrupt-redirect) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) * - **0xF000_1002** - **NMI** - **0x0** - **Fast Interrupt non-DCCM region** - [](interrupts.md#fast-interrupt-redirect) and [](memory-map.md#non-maskable-interrupt-nmi-signal-and-vector) ::: :::{note} All other values are reserved. ::: [^fn-mscause-register-1]: Relative priority of load/store exceptions (0: highest priority). [^fn-mscause-register-2]: Fetch access not within ICCM address range. [^fn-mscause-register-3]: Trigger hit can also be observed in *hit* bit of mcontrol register (see {numref}`tab-mcontrol`). [^fn-mscause-register-4]: Load/store access not within DCCM or PIC memory-mapped register address ranges. [^fn-mscause-register-5]: If a load or store access crosses the upper boundary of either the DCCM or PIC memory-mapped register address range, the error address reported in the mtval register is the base address of the access, not the address of the first byte outside the DCCM or PIC range. Note that firmware cannot recover from this access fault independent of which address is reported. [^fn-mscause-register-6]: PIC load/store not word-sized or address not word-aligned. [^fn-mscause-register-7]: Core external timer ## Memory Address Map {numref}`tab-veer-el2-memory-address-map` summarizes an example of the VeeR EL2 memory address map, including regions as well as start and end addresses for the various memory types. :::{list-table} VeeR EL2 Memory Address Map (Example) :name: tab-veer-el2-memory-address-map :header-rows: 1 * - **Region** - **Start Address** - **End Address** - **Memory Type** * - 0x0 - 0x0000_0000 - 0x0003_FFFF - Reserved * - 0x0 - 0x0004_0000 - 0x0005_FFFF - ICCM (region: 0, offset: 0x4000, size: 128KB) * - 0x0 - 0x0006_0000 - 0x0007_FFFF - Reserved * - 0x0 - 0x0008_0000 - 0x0009_FFFF - DCCM (region: 0, offset: 0x8000, size: 128KB) * - 0x0 - 0x000A_0000 - 0x0FFF_FFFF - Reserved * - 0x1 - 0x1000_0000 - 0x1FFF_FFFF - System memory-mapped CSRs * - 0x2 - 0x2000_0000 - 0x2FFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0x3 - 0x3000_0000 - 0x3FFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0x4 - 0x4000_0000 - 0x4FFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0x5 - 0x5000_0000 - 0x5FFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0x6 - 0x6000_0000 - 0x6FFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0x7 - 0x7000_0000 - 0x7FFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0x8 - 0x8000_0000 - 0x8FFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0x9 - 0x9000_0000 - 0x9FFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0xA - 0xA000_0000 - 0xAFFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0xB - 0xB000_0000 - 0xBFFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0xC - 0xC000_0000 - 0xCFFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0xD - 0xD000_0000 - 0xDFFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0xE - 0xE000_0000 - 0xEFFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces * - 0xF - 0xF000_0000 - 0xFFFF_FFFF - System SRAMs, system ROMs, and system memory-mapped I/O device interfaces ::: ## Behavior of Loads to Side-Effect Addresses Loads with potential side-effects do not stall the pipeline and may be committed before the data is returned from the system bus. Other loads and stores in the pipeline continue to be executed unless an instruction uses data from a pending side-effect load. Stalling the instruction control flow until a side-effect load has completed may be accomplished by either issuing a fence instruction or by generating a dependency on the load's data. ## Partial Writes Rules for partial writes handling are: * **Core-local addresses:** The core performs a read-modify-write operation and updates ECC to core-local memories (i.e., I- and DCCMs). * **SoC addresses:** The core indicates the valid bytes for each bus write transaction. The addressed SoC memory or device performs a read-modify-write operation and updates its ECC. ## Expected SoC Behavior for Accesses The VeeR EL2 core expects that the SoC responds to all system bus access requests it receives from the core. System bus accesses include instruction fetches, load/store data accesses as well as debug system bus accesses. A response may either be returning the requested data (e.g., instructions sent back to the core for fetches or data for loads), an acknowledgement indicating the successful completion of a bus transaction (e.g., acknowledging a store), an error response (e.g., an error indication in response to an attempt to access an unmapped address). If the SoC does not respond to every single bus transaction, the core may hang. ## Speculative Bus Accesses Deep core pipelines require a certain degree of speculation to maximize performance. The sections below describe instruction and data speculation in the VeeR EL2 core. Note that speculative accesses to memory addresses with side effects may be entirely avoided by adding the buildargument-selected and -configured memory protection mechanism described in [](memory-map.md#memory-protection). ### Instructions Instruction cache misses on VeeR EL2 are speculative in nature. The core may issue speculatively fetch accesses on the IFU bus interface for an instruction cache miss in the following cases: * due to an earlier exception or interrupt, * due to an earlier branch mispredict, * due to an incorrect branch prediction, and * due to an incorrect Return Address Stack (RAS) prediction. Issuing speculative accesses on the IFU bus interface is benign as long as the platform is able to handle accesses to unimplemented memory and to prevent accesses to SoC components with read side effects by returning random data and/or a bus error condition. The decision of which addresses are unimplemented and which addresses with potential side effects need to be protected is left to the platform. Instruction fetch speculation can be limited, though not entirely avoided, by turning off the core's branch predictor including the return address stack. Writing a '1' to the *bpd* bit in the `mfdc` register (see {numref}`tab-feature-disable-cr`) disables branch prediction including RAS. ### Data The VeeR EL2 core does not issue any speculative data accesses on the LSU bus interface. ## DMA Slave Port The Direct Memory Access (DMA) slave port is used for read/write accesses to core-local memories initiated by external masters. For example, external masters could be DMA controllers or other CPU cores located in the SoC. ### Access The DMA slave port allows read/write access to the core's ICCM and DCCM. However, the PIC memory-mapped control registers are not accessible via the DMA port. ### Write Alignment Rules For writes to the ICCM and DCCM through the DMA slave port, accesses must be 32- or 64-bit aligned, and 32 bits (word) or 64 bits (double-word), respectively, wide to avoid read-modify-write operations for ECC generation. More specifically, DMA write accesses to the ICCM or DCCM must have a 32- or 64-bit access size and be aligned to their respective size. The only write byte enable values allowed for AXI4 are 0x0F, 0xF0, and 0xFF. ### Quality Of Service Accesses to the ICCM and DCCM by the core have higher priority if the DMA FIFO is not full. However, to avoid starvation, the DMA slave port's DMA controller may periodically request a stall to get access to the pipe if a DMA request is continuously blocked. The *dqc* field in the `mfdc` register (see {numref}`tab-feature-disable-cr`) specifies the maximum number of clock cycles a DMA access request waits at the head of the DMA FIFO before requesting a bubble to access the pipe. For example, if *dqc* is 0, a DMA access requests a bubble immediately (i.e., in the same cycle); if *dqc* is 7 (the default value), a waiting DMA access requests a bubble on the 8th cycle. For a DMA access to the ICCM, it may take up to 3 additional cycles25 before the access is granted. Similarly, for a DMA access to the DCCM, it may take up to 4 additional cycles before the access is granted. ### Ordering Of Core and DMA Accesses Accesses to the DCCM or ICCM by the core and the DMA slave port are asynchronous events relative to one another. There are no ordering guarantees between the core and the DMA slave port accessing the same or different addresses. ## Reset Signal and Vector The core provides a 31-bit wide input bus at its periphery for a reset vector. The SoC must provide the reset vector on the `rst_vec[31:1]` bus, which could be hardwired or from a register. The `rst_l` input signal is active-low, asynchronously asserted, and synchronously deasserted (see also [](clocks.md#reset)). When the core is reset, it fetches the first instruction to be executed from the address provided on the reset vector bus. Note that the applied reset vector must be pointing to the ICCM, if enabled, or a valid memory address, which is within an enabled instruction access window if the memory protection mechanism (see [](memory-map.md#memory-protection)) is used. :::{note} The core's 31 general-purpose registers (`x1 - x31`) are cleared on reset. ::: ## Non-Maskable Interrupt (NMI) Signal and Vector The core provides a 31-bit wide input bus at its periphery for a non-maskable interrupt (NMI) vector. The SoC must provide the NMI vector on the `nmi_vec[31:1]` bus, either hardwired or sourced from a register. :::{note} NMI is entirely separate from the other interrupts and not affected by the selection of Direct vs Vectored mode. ::: The SoC may trigger an NMI by asserting the low-to-high edge-triggered, `asynchronous nmi_int` input signal. This signal must be asserted for at least two full core clock cycles to guarantee it is detected by the core since shorter pulses might be dropped by the synchronizer circuit. Furthermore, the `nmi_int` signal must be deasserted for a minimum of two full core clock cycles and then reasserted to signal the next NMI request to the core. If the SoC does not use the pin-asserted NMI feature, it must hardwire the `nmi_int` input signal to 0. In addition to NMIs triggered by the SoC, a core-internal NMI request is signaled when a D-bus store or non-blocking load error has been detected. When the core receives either an SoC-triggered or a core-internal NMI request, it fetches the next instruction to be executed from the address provided on the NMI vector bus. The reason for the NMI request is reported in the `mcause` register according to {numref}`tab-summary-nmi-mcause-values`. :::{list-table} Summary of NMI mcause Values :name: tab-summary-nmi-mcause-values :header-rows: 1 * - **Value mcause[31:0]** - **Description** - **Section** * - 0x0000_0000 - NMI pin assertion (`nmi_int` input signal) - see above * - 0xF000_0000 - Machine D-bus store error NMI - [](memory-map.md#imprecise-bus-error-non-maskable-interrupt) * - 0xF000_0001 - Machine D-bus non-blocking load error NMI - [](memory-map.md#imprecise-bus-error-non-maskable-interrupt) * - 0xF000_1000 - Machine Fast Interrupt double-bit ECC error NMI - [](interrupts.md#fast-interrupt-redirect) * - 0xF000_1001 - Machine Fast Interrupt DCCM region access error NMI - [](interrupts.md#fast-interrupt-redirect) * - 0xF000_1002 - Machine Fast Interrupt non-DCCM region NMI - [](interrupts.md#fast-interrupt-redirect) ::: :::{note} NMIs are typically fatal! Section 3.4 of the RISC-V Privileged specification [[2]](intro.md#ref-2) states that NMIs are only used for hardware error conditions and cause an immediate jump to the address at the NMI vector running in M-mode regardless of the state of a hart's interrupt enable bits. The NMI can thus overwrite state in an active M-mode interrupt handler and normal program execution cannot resume. Unlike resets, NMIs do not reset hart state, enabling diagnosis, reporting, and possible containment of the hardware error. Because NMIs are not maskable, the NMI handling routine performing diagnosis and reporting is itself susceptible to further NMIs, possibly making any such activity meaningless and erroneous in the face of error storms. ::: ## Software Interrupts The VeeR EL2 core provides a software-interrupt input signal for its hart (see `soft_int` in {numref}`tab-core-complex-signals`). The `soft_int` signal is an active-high, level-sensitive, asynchronous input signal which feeds the *msip* (machine software-interrupt pending) bit of the standard RISC-V `mip` register (see {numref}`tab-machine-interrupt-pending-register`). When the *msie* (machine software-interrupt enable) bit of the standard RISC-V `mie` register (see {numref}`tab-machine-interrupt-enable-register`) is set, a machine software interrupt occurs if the *msip* bit of the `mip` register is asserted. The SoC must implement Machine Software Interrupt (MSI) memory-mapped I/O registers. These registers provide interrupt control bits which are directly connected to the respective `soft_int` pins of each core. Writing to the corresponding bit of one of these registers enables remote harts to trigger machine-mode interprocessor interrupts. Each hart can read its own `mhartid` register (see [](adaptations.md#machine-hardware-thread-id-register-mhartid)) to determine the memory address of the associated memory-mapped MSI register within the platform. In this manner, an interrupt service routine can reset the corresponding memory-mapped MSI register bit before returning from a software interrupt. ================================================ FILE: docs/source/overview.md ================================================ # Core Overview This chapter provides a high-level overview of the VeeR EL2 core and core complex. VeeR EL2 is a machinemode (M-mode) and usermode (U-mode), 32-bit CPU small core which supports RISC-V's integer (I), compressed instruction (C), multiplication and division (M), and instruction-fetch fence, CSR, and subset of bit manipulation instructions (Z) extensions. The core contains a 4-stage, scalar, in-order pipeline. ## Features The VeeR EL2 core complex's feature set includes: - RV32IMC-compliant RISC-V core with branch predictor - Optional instruction and data closely-coupled memories with ECC protection (load-to-use latency of 1 cycle for smaller and 2 cycles for larger memories) - Optional 2- or 4-way set-associative instruction cache with parity or ECC protection (32- or 64-byte line size) - Optional programmable interrupt controller supporting up to 255 external interrupts - Four system bus interfaces for instruction fetch, data accesses, debug accesses, and external DMA accesses to closely-coupled memories (configurable as 64-bit AXI4 or AHB-Lite) - Core debug unit compliant with the RISC-V Debug specification [[3]](intro.md#ref-3) - 600MHz target frequency (for 16nm technology node) ## Core Complex {numref}`fig-core-complex` depicts the core complex and its functional blocks which are described further in section [](overview.md#functional-blocks). :::{figure-md} fig-core-complex ![VeeR Core Complex](img/core_complex.png) VeeR Core Complex ::: ## Functional Blocks The VeeR EL2 core complex's functional blocks are described in the following sections in more detail. ### Core {numref}`fig-core-pipeline` depicts the scalar 4-stage core with one execution pipeline, one load/store pipeline, one multiplier pipeline, and one out-of-pipeline divider. There are two stall points in the pipeline: 'Fetch' and 'Decode'. The diagram also shows how VeeR EH1's logic stages have been shifted up and merged into 4 stages named Fetch (F), Decode (D), Execute/Memory (X/M), and Retire (R). Also shown is additional logic such as a new branch adder in the D stage. The branch mispredict penalty is either 1 or 2 cycles in VeeR EL2. The merged F stage performs the program counter calculation and the I-cache/ICCM memory access in parallel. The load pipeline has been moved up so that the DC1 memory address generation (AGU) logic is now combined with align and decode logic to enable a DCCM memory access to start at the beginning of the M stage. The design supports a load-to-use of 1 cycle for smaller memories and a load-to-use of 2 cycles for larger memories. For 1-cycle load-to-use, the memory is accessed and the load data aligned and formatted for the register file and forwarding paths, all in the single-cycle M stage. For 2-cycle load-to-use, almost the entire M stage is allocated to the memory access, and the DC3/DC4 logic combined into the R stage is used to perform the load align and formatting for the register file and forwarding paths. EX3 and EX4/WB are combined into the R stage and primarily used for commit and writeback to update the architectural registers. :::{figure-md} fig-core-pipeline ![VeeR EL2 Core Pipeline](img/core_pipeline.png) VeeR EL2 Core Pipeline ::: ## Standard Extensions The VeeR EL2 core implements the following RISC-V standard extensions: :::{list-table} VeeR EL2's RISC-V Standard Extensions :name: tab-riscv-std-ext :header-rows: 1 * - Extension - Description - References * - M - Integer multiplication and division - Chapter 7 in [[1]](intro.md#ref-1) * - C - Compressed instructions - Chapter 16 in [[1]](intro.md#ref-1) * - Zicsr - Control and status register (CSR) instructions - Chapter 9 in [[1]](intro.md#ref-1) * - Zifencei - Instruction-fetch fence - Chapter 3 in [[1]](intro.md#ref-1) * - Zba [^fn-standard-extensions-1] (address calculation) (frozen) - Bit manipulation instructions - Chapter 2 in [[4]](intro.md#ref-4) * - Zbb [^fn-standard-extensions-2] (base) (frozen) - Bit manipulation instructions - Chapter 2 in [[4]](intro.md#ref-4) * - Zbc [^fn-standard-extensions-3] (carry-less multiply) (frozen) - Bit manipulation instructions - Chapter 2 in [[4]](intro.md#ref-4) * - Zbs [^fn-standard-extensions-4] (single-bit) (frozen) - Bit manipulation instructions - Chapter 2 in [[4]](intro.md#ref-4) * - Zbe [^fn-standard-extensions-5] (bit compress/ decompress) (stable) - Bit manipulation instructions - Chapter 2 in [[4]](intro.md#ref-4) * - Zbf [^fn-standard-extensions-6] (bit-field place) (stable) - Bit manipulation instructions - Chapter 2 in [[4]](intro.md#ref-4) * - Zbp [^fn-standard-extensions-7] (bit permutation) (stable) - Bit manipulation instructions - Chapter 2 in [[4]](intro.md#ref-4) * - Zbr [^fn-standard-extensions-8] (CRC) (stable) - Bit manipulation instructions - Chapter 2 in [[4]](intro.md#ref-4) ::: * `frozen` specified means that the extensions are not expected to change. * `stable` mean that the marked extension may still change. [^fn-standard-extensions-1]: List of Zba instructions (as of 1/20/21, "frozen"): sh1add, sh2add, sh3add [^fn-standard-extensions-2]: List of Zbb instructions (as of 1/20/21, "frozen"): clz, ctz, cpop, min, minu, max, maxu, sext.b, sext.h, zext.h, andn, orn, xnor, rol, ror, rori, rev8, orc.b [^fn-standard-extensions-3]: List of Zbc instructions (as of 1/20/21, "frozen"): clmul, clmulh, clmulr [^fn-standard-extensions-4]: List of Zbs instructions (as of 1/20/21, "frozen"): bset, bseti, bclr, bclri, binv, binvi, bext, bexti [^fn-standard-extensions-5]: List of Zbe instructions (as of 1/20/21, "stable"): bcompress, bdecompress, pack, packh [^fn-standard-extensions-6]: List of Zbf instructions (as of 1/20/21, "stable"): bfp, pack, packh [^fn-standard-extensions-7]: List of Zbp instructions (as of 1/20/21, "stable"): andn, orn, xnor, pack, packu, packh, rol, ror, rori, grev, grevi, gorc, gorci, shfl, shfli, unshfl, unshfli, xperm.n, xperm.b, xperm.h [^fn-standard-extensions-8]: List of Zbr instructions (as of 1/20/21, "stable"): crc32.b, crc32c.b, crc32.h, crc32c.h, crc32.w, crc32c.w ================================================ FILE: docs/source/performance.md ================================================ # Performance Monitoring This chapter describes the performance monitoring features of the VeeR EL2 core. ## Features VeeR EL2 provides these performance monitoring features: * Four standard 64-bit wide event counters * Standard separate event selection for each counter * Standard selective count enable/disable controllability * Standard synchronized counter enable/disable controllability * Standard cycle counter * Standard retired instructions counter * Support for standard SoC-based machine timer registers ## Control/Status Registers ### Standard RISC-V Registers A list of performance monitoring-related standard RISC-V CSRs with references to their definitions: * Machine Hardware Performance Monitor (`mcycle{|h}`, `minstret{|h}`, `mhpmcounter3{|h}`- `mhpmcounter31{|h}`, and `mhpmevent3`-`mhpmevent31`) (see Section 3.1.11 in [[2]](intro.md#ref-2)) * Machine Counter-Inhibit Register [^fn-performance-1] (`mcountinhibit`) (see Section 3.1.13 in [[2]](intro.md#ref-2)) * Machine Timer Registers (`mtime` and `mtimecmp`) (see Section 3.1.10 in [[2]](intro.md#ref-2)) :::{note} `mtime` and `mtimecmp` are memory-mapped registers which must be provided by the SoC. ::: [^fn-performance-1]: The standard `mcountinhibit` register which was recently added to [[2]](intro.md#ref-2) replaces the non-standard mgpmc register of the previous VeeR generation. The `mcountinhibit` register provides the same functionality as the `mgpmc` register did, but at a much finer granularity (i.e., an enable/disable control bit per standard hardware performance counter instead of a single control bit for the `mhpmcounter3` - `mhpmcounter6` counters). ## Counters Only event counters 3 to 6 (`mhpmcounter3{|h}`-`mhpmcounter6{|h}`) and their corresponding event selectors (`mhpmevent3`-`mhpmevent6`) are functional on VeeR EL2. Event counters 7 to 31 (`mhpmcounter7{|h}`-`mhpmcounter31{|h}`) and their corresponding event selectors (`mhpmevent7`-`mhpmevent31`) are hardwired to '0'. ## Count-Impacting Conditions A few comments to consider on conditions that have an impact on the performance monitor counting: * While in the pmu/fw-halt power management state, performance counters (including the `mcycle` counter) are disabled. * While in debug halt (db-halt) state, the *stopcount* bit of the `dcsr` register (see [](debugging.md#debug-control-and-status-register-dcsr)) determines if performance counters are enabled. * While in the pmu/fw-halt power management state or the debug halt (db-halt) state with the stopcount bit set, DMA accesses are allowed, but not counted by the performance counters. It would be up to the bus master to count accesses while the core is in a halt state. * While executing PAUSE, performance counters are enabled. Also, it is recommended that the performance counters are disabled (using the `mcountinhibit` register) before the counters and event selectors are modified, and then reenabled again. This minimizes the impact of reading and writing the counter and event selector CSRs on the event count values, specifically for the CSR read/write events (i.e., events #16 and #17). In general, performance counters are incremented after a read access to the counter CSRs, but before a write access to the counter CSRs. ## Events {numref}`tab-list-of-countable-events` provides a list of the countable events. :::{note} The event selector registers `mhpmevent3`-`mhpmevent6` have WARL behavior. When writing either a value marked as 'Reserved' or larger than the highest supported event number, the event selector is set to '0' (i.e., no event counted). ::: :::{list-table} List of Countable Events :name: tab-list-of-countable-events * - **Event No** - **Event Name** - **Description** * - 0 - - Reserved (no event counted) * - **Events counted while in Active (C0) state** - - * - Legend: IP = In-Pipe; OOP = Out-Of-Pipe - - * - 1 - cycles clocks active - Number of cycles clock active (OOP) * - 2 - I-cache hits - Number of I-cache hits (OOP, speculative, valid fetch & hit) * - 3 - I-cache misses - Number of I-cache misses (OOP, valid fetch & miss) * - 4 - instr committed - all - Number of all (16b+32b) instructions committed (IP, non-speculative, 0/1) * - 5 - instr committed - 16b - Number of 16b instructions committed (IP, non-speculative, 0/1) * - 6 - instr committed - 32b - Number of 32b instructions committed (IP, non-speculative, 0/1) * - 7 - instr aligned - all - Number of all (16b+32b) instructions aligned (OOP, speculative, 0/1) * - 8 - instr decoded - all - Number of all (16b+32b) instructions decoded (OOP, speculative, 0/1) * - 9 - muls committed - Number of multiplications committed (IP, 0/1) * - 10 - divs committed - Number of divisions and remainders committed (IP, 0/1) * - 11 - loads committed - Number of loads committed (IP, 0/1) * - 12 - stores committed - Number of stores committed (IP, 0/1) * - 13 - misaligned loads - Number of misaligned loads (IP, 0/1) * - 14 - misaligned stores - Number of misaligned stores (IP, 0/1) * - 15 - alus committed - Number of ALU [^fn-performance-2] operations committed (IP, 0/1) * - 16 - CSR read - Number of CSR read instructions committed (IP, 0/1) * - 17 - CSR read/write - Number of CSR read/write instructions committed (IP, 0/1) * - 18 - CSR write rd==0 - Number of CSR write rd==0 instructions committed (IP, 0/1) * - 19 - `ebreak` - Number of ebreak instructions committed (IP, 0/1) * - 20 - `ecall` - Number of ecall instructions committed (IP, 0/1) * - 21 - `fence` - Number of fence instructions committed (IP, 0/1) * - 22 - `fence.i` - Number of fence.i instructions committed (IP, 0/1) * - 23 - `mret` - Number of mret instructions committed (IP, 0/1) * - 24 - branches committed - Number of branches committed (IP) * - 25 - branches mispredicted - Number of branches mispredicted (IP) * - 26 - branches taken - Number of branches taken (IP) * - 27 - unpredictable branches - Number of unpredictable branches (IP) * - 28 - cycles fetch stalled - Number of cycles fetch ready but stalled (OOP) * - 29 - - Reserved * - 30 - cycles decode stalled - Number of cycles one or more instructions valid in IB but decode stalled (OOP) * - 31 - cycles postsync stalled - Number of cycles postsync stalled at decode (OOP) * - 32 - cycles presync stalled - Number of cycles presync stalled at decode (OOP) * - 33 - - Reserved * - 34 - cycles SB/WB stalled (lsu_store_stall_any) - Number of cycles decode stalled due to SB or WB full (OOP) * - 35 - cycles DMA DCCM transaction stalled (dma_dccm_stall_any) - Number of cycles DMA stalled due to decode for load/store (OOP) * - 36 - cycles DMA ICCM transaction stalled (dma_iccm_stall_any) - Number of cycles DMA stalled due to fetch (OOP) * - 37 - exceptions taken - Number of exceptions taken (IP) * - 38 - timer interrupts taken - Number of timer [^fn-performance-3] interrupts taken (IP) * - 39 - external interrupts taken - Number of external interrupts taken (IP) * - 40 - TLU flushes (flush lower) - Number of TLU flushes (flush lower) (IP) * - 41 - branch error flushes - Number of branch error flushes (IP) * - 42 - I-bus transactions - instr - Number of instr transactions on I-bus interface (OOP) * - 43 - D-bus transactions - ld/st - Number of ld/st transactions on D-bus interface (OOP) * - 44 - D-bus transactions - misaligned - Number of misaligned transactions on D-bus interface (OOP) * - 45 - I-bus errors - Number of transaction errors on I-bus interface (OOP) * - 46 - D-bus errors - Number of transaction errors on D-bus interface (OOP) * - 47 - cycles stalled due to I- bus busy - Number of cycles stalled due to AXI4 or AHB-Lite I-bus busy (OOP) * - 48 - cycles stalled due to D- bus busy - Number of cycles stalled due to AXI4 or AHB-Lite D-bus busy (OOP) * - 49 - cycles interrupts disabled - Number of cycles interrupts disabled (MSTATUS.MIE==0) (OOP) * - 50 - cycles interrupts stalled while disabled - Number of cycles interrupts stalled while disabled (MSTATUS.MIE==0) (OOP) * - 51 - 53 - - Reserved * - 54 - bitmanip committed - Number of bit-manipulation operations committed (IP, 0/1) * - 55 - D-bus loads committed - Number of load instructions to D-bus committed (IP, 0/1) * - 56 - D-bus stores committed - Number of store instructions to D-bus committed (IP, 0/1) * - 57 - 511 - - Reserved * - **Events counted while in Active (C0) or Sleep (C3) states** - - * - 512 - cycles in Sleep (C3) state - Number of cycles in Sleep (C3) state (OOP) * - 513 - DMA reads (all) - Total number of DMA slave read transactions (OOP) * - 514 - DMA writes (all) - Total number of DMA slave write transactions (OOP) * - 515 - DMA reads to DCCM - Number of DMA slave read transactions to DCCM (OOP) * - 516 - DMA writes to DCCM - Number of DMA slave write transactions to DCCM (OOP) ::: :::{note} If an event shown as 'Reserved' is selected, no error is reported but counter is not incrementing. ::: [^fn-performance-2]: NOP is an ALU operation. WFI is implemented as a NOP in VeeR EL2 and, hence, counted as an ALU operation was well. [^fn-performance-3]: Events counted include interrupts triggered by the standard RISC-V platform-level timer as well as by the two internal timers. ================================================ FILE: docs/source/physical-memory-protection.md ================================================ # Physical Memory Protection The Physical Memory Protection unit implemented in the VeeR EL2 Core is compliant with "Section 3.7 Physical Memory Protection" of [[5]](intro.md#ref-5). RISC-V introduces additional regulatory documents regarding memory protection: - [Supervisor mode PMP (SPMP)](https://github.com/riscv/riscv-spmp/blob/main/rv-spmp-spec.pdf) - [PMP enhancements (Smepmp)](https://github.com/riscv/riscv-tee/blob/main/Smepmp/Smepmp.pdf) ## Theory of Operation The PMP module adds a set of CSRs which define memory regions and Read/Write/Execute (RWX) access permissions. For each memory access, the PMP module checks if accessed memory is on the allowlist. In case of impermissible memory access, a precise exception is thrown and execution flow is switched to the trap handler. The PMP distinguishes 3 types of memory accesses: instruction fetch, data load and data store. ## Physical Memory Protection CSRs The `pmpcfgX` and `pmpaddrX` CSRs are implemented in the [*el2_dec_tlu_ctl* module](../../design/dec/el2_dec_tlu_ctl.sv). CSR address decoding is generated from either [*csrdecode_m*](../../design/dec/csrdecode_m) (Machine mode) or [*csrdecode_mu*](../../design/dec/csrdecode_mu) (Machine and User mode) description file. The number of `pmpcfgX` registers is always 4 times smaller than the number of PMP entries, which are configurable using the `-set=pmp_entires=N` option, where *N* can be 0, 16 or 64. :::{list-table} CSR configurations for RV-32 :name: tab-riscv-pmp-csr-configuration-table :header-rows: 1 :align: left * - Number of PMP entries - Number of *pmpcfgX* CSRs - Number of *pmpaddrX* CSRs * - 0 - 0 - 0 * - 16 - 4 - 16 * - 64 - 16 - 64 ::: ### Configuration Registers (pmpcfgX) Each `pmpcfgX` register holds a configuration for four PMP entries, with a byte used for each entry. :::{list-table} Decoding of the *pmpcfgX* register :name: tab-riscv-pmpcfgx-register :header-rows: 1 :align: left * - **Bit** - 7 - 6 - 5 - 4 - 3 - 2 - 1 - 0 * - **Flag** - *L* - *0* - *0* - *A[1]* - *A[0]* - *X* - *W* - *R* ::: Meaning of bit flags: - *L* - lock bit; when set to *1*, given entry cannot be changed (both configuration and address) until hart reset - *0* - unused bits, always set to *0* - *A[1:0]* - encodes address matching mode (*OFF*, *TOR*, *NA4*, *NAPOT*) - *X* - execute permission; when set to *1*, allows instruction fetch from the corresponding address region; otherwise memory access will result in an instruction access-fault exception - *W* - write permission; when set to *1*, allows data store to the corresponding address region; otherwise memory access will result in a store access-fault exception - *R* - read permission; when set to *1*, allows data load from the corresponding address region; otherwise memory access will result in a load access-fault exception. ### Address Registers (pmpaddrX) PMP address registers (`pmpaddrX`) encode bits 33 to 2 (`address[33:2]`) in physical memory. This address defines protected memory region boundaries, further interpreted according to address matching values encoded by bits 4 and 3 of the `pmpcfgX` register: - *00* OFF Null region (disabled) - *01* TOR Top of range - *10* NA4 Naturally aligned four-byte region - *11* NAPOT Naturally aligned power-of-two region, >=8 bytes ## Exceptions In case of impermissible memory access, an exception is raised and the exception code is stored in the `mcause` CSR register (*0x342*). :::{list-table} PMP related exception codes :name: tab-riscv-pmp-exceptions :header-rows: 1 :widths: 14 14 36 * - **Interrupt flag (*mcause[MXLEN-1]*)** - **Exception Code (*mcause[MXLEN-2:0]*)** - **Exception description** * - *0* - *1* - Instruction access fault (cannot read instruction from protected region) * - *0* - *5* - Load access fault (cannot load data from protected region) * - *0* - *7* - Store/Atomic Memory Operation access fault (cannot store data to protected region) ::: Whenever a PMP access fault exception is raised, the machine secondary cause register (`mscause`) value is *0x03* indicating "access out of MPU range". ## PMP module The PMP module is implemented in [el2_pmp.sv](../../design/el2_pmp.sv). It is meant to be connected to the: - CSR configuration table - CSR addresses table - configuration inputs for each channel (marking permissions to be checked on a given channel) - address inputs for each channel (one for IFU, one for LSU) - error outputs for each channel The following functionality has been implemented: - decoding address ranges (start address and mask) from address CSRs depending on the address matching mode for a given entry - comparing addresses coming from a channel to defined ranges - asserting error flags for given channels depending on permissions from the first matching range. Error handling is performed using existing logic in IFU and LSU modules, reusing previously implemented mechanisms. :::{figure-md} riscv_pmp_block_diagram ![riscv_pmp_block_diagram](img/19-riscv_pmp_block_diagram.png) PMP integration with other modules of the VeeR EL2 core. ::: ## Verification The PMP module is tested with: * [RTL tests](../../verification/block/pmp/testbench.py) * [software smoke tests](../../testbench/tests/pmp/main.c) * [RISC-V DV tests](../../.github/workflows/test-riscv-dv.yml) ## PMP check example In this example we enforce the following permissions: - *0x00000000* - *0x00000FFF* - deny reads, writes, execution - *0x00001000* - *0x00001FFF* - allow reads, writes, execution First, let's configure the 2 address regions by writing 2 bytes to the lower 16 bits of the `pmpcfg0` register (each region configuration uses a byte) PMP configuration registers should be set to: - `pmpcfg0[7:0]` = *0b00001000* - non-locked entry, top-of-range address matching, all memory access denied. - `pmpcfg0[15:8]` = *0b00001111* - non-locked entry, top-of-range address matching, all memory access permitted. To select top-of-range matching, bits 3 and 4 of the configuration field are set to *0b01*, which creates a region starting with the address from the previous entry `pmpaddrX-1` and ending at an address in the `pmpaddrX` register, decremented by one. In case of the first entry on the list, the *0x00000000* address is used as boundary. After selecting the addressing mode, we can calculate values of `pmpaddr0` and `pmpaddr1` registers, which will define boundaries of regions. Addresses stored in `pmpaddrX` CSRs contain bits *[33:2]* of the memory address. Thus to select a specific address, it must be shifted by 2 bits to the right before writing the value to the register: * `pmpaddr0` should be `(0x00001000 >> 2) = 0x00000400`, so that it matches the memory region from *0x00000000* to *0x00000FFF*. * `pmpaddr1` should be `(0x00002000 >> 2) = 0x00000800`, so that it matches the memory region from *0x00001000* (which is the top address of the previous entry) to *0x00001FFF*. With this configuration, all memory accesses to the first region (*0x00000000* - *0x00000FFF*) will fail and trigger an exception. The exception code can be read to determine the type of the failed operation (instruction fetch, data load or data store). On the other hand, all memory accesses to the second region (*0x00001000* - *0x00001FFF*) will be executed without errors. ================================================ FILE: docs/source/power.md ================================================ # Power Management and Multi-Core Debug Control This chapter specifies the power management and multi-core debug control functionality provided or supported by the VeeR EL2 core. Also documented in this chapter is how debug may interfere with core power management. ## Features VeeR EL2 supports and provides the following power management and multi-core debug control features: * Support for three system-level power states: Active (C0), Sleep (C3), Power Off (C6) * Firmware-initiated halt to enter sleep state * Fine-grain clock gating in active state * Enhanced clock gating in sleep state * Halt/run control interface to/from SoC Power Management Unit (PMU) * Signal indicating that core is halted * Halt/run control interface to/from SoC debug Multi-Processor Controller (MPC) to enable cross-triggering in multi-core chips * Timeout-based mechanism to force Debug Halt state by terminating hung bus transactions * Signals indicating that core is in Debug Mode and core hit a breakpoint * PAUSE feature to help avoid firmware spinning ## Core Control Interfaces VeeR EL2 provides two control interfaces, one for power management and one for multi-core debug control, which enable the core to be controlled by other SoC blocks. ### Power Management The power management interface enables an SoC-based Power Management Unit (PMU) to: * Halt (i.e., enter low-power sleep state) or restart (i.e., resume execution) the core, and * get an indication when the core has gracefully entered the sleep state. The power management interface signals are described in {numref}`tab-veer-el2-power-ctrl-status-signals`. ### Multi-Core Debug Control The multi-core debug control interface enables an SoC-based Multi-Processor Controller (MPC) to: * Control the reset state of the core (i.e., either start executing or enter Debug Mode), * halt (i.e., enter Debug Mode) or restart (i.e., resume execution) the core, * get an indication when the core is in Debug Mode, and * cross-trigger other cores when this core has entered Debug Mode due to a software or a hardware breakpoint. The multi-core debug control interface signals are described in {numref}`tab-veer-el2-multi-core-debug-ctrl-status-signals`. ## Power States From a system's perspective, the core may be placed in one of three power states: Active (C0), Sleep (C3), and Power Off (C6). Active and Sleep states require hardware support from the core, but in the Power Off state the core is power-gated so no special hardware support is needed. {numref}`fig-activity-states` depicts and {numref}`tab-core-activity-states` describes the core activity states as well as the events to transition between them. :::{figure-md} fig-activity-states ![Activity states](img/activity_states.png) VeeR EL2 Core Activity States ::: :::{note} 'Core Quiesced' implies that no new instructions are executed and all outstanding core-initiated bus transactions are completed (i.e., the unified buffer is empty, and all outstanding I-cache misses are finished). Note that the store queue and the DMA FIFO might not be empty due to on-going DMA transactions. ::: :::{list-table} Debug Resume Requests :name: tab-debug-resume-requests :header-rows: 1 * - Core-Internal State - - - - - - **Comments** * - **Debug Resume** - **Debug Halt** - **MPC Halt** - **MPC Run** - **Halted (This Cycle)** - **Halted (Next Cycle)** - * - 0 - 0 - 0 - 0 - 0 - 0 - No request for Debug Mode entry * - 0 - 0 - 0 - 1 - - - No action required from core (requires coordination outside of core) * - 0 - 0 - 1 - 0 - 1 - 1 - Waiting for MPC Run (core remains in ‘db-halt’ state) * - 0 - 0 - 1 - 1 - 1 - 0 - MPC Run Ack * - 0 - 1 - 0 - 0 - 1 - 1 - Waiting for Debug Resume (core remains in ‘db-halt’ state) * - 0 - 1 - 0 - 1 - - - No action required from core (requires coordination outside of core) * - 0 - 1 - 1 - 0 - 1 - 1 - Waiting for both MPC Run and Debug Resume (core remains in ‘db-halt’ state) * - 0 - 1 - 1 - 1 - 1 - 1 - Waiting for Debug Resume (core remains in ‘db-halt’ state) * - 1 - 0 - 0 - 0 - - - No action required from core (requires coordination outside of core) * - 1 - 0 - 0 - 1 - - - No action required from core (requires coordination outside of core) * - 1 - 0 - 1 - 0 - - - No action required from core (requires coordination outside of core) * - 1 - 0 - 1 - 1 - - - No action required from core (requires coordination outside of core) * - 1 - 1 - 0 - 0 - 1 - 0 - Debug Resume Ack * - 1 - 1 - 0 - 1 - - - No action required from core (requires coordination outside of core) * - 1 - 1 - 1 - 0 - 1 - 1 - Waiting for MPC Run (core remains in ‘db-halt’ state) * - 1 - 1 - 1 - 1 - 1 - 0 - Debug Resume Ack and MPC Run Ack ::: :::{note} While in 'db-halt' state, hardware ignores Debug Resume requests if the corresponding 'Debug Halt' state is not '1'. Likewise, hardware ignores MPC Debug Run requests if the corresponding 'MPC Halt' state is not '1'. ::: :::{note} The core-internal state bits are cleared upon exiting Debug Mode. ::: :::{note} In the time period between an MPC Debug Halt request and an MPC Debug Run request, a core debug singlestep action is stalled but stays pending. ::: :::{note} Even if the core is already in Debug Mode due to a previous MPC Debug Halt request, a core debugger must initiate a debug halt (i.e., Core Debug Halt request) before it may start issuing other debug commands. However, if Debug Mode was entered due to a core debug breakpoint, a Core Debug Halt request is not required. ::: :::{note} An MPC Debug Halt request may only be signaled when the core is either not in Debug Mode or is already in Debug Mode due to a previous Core Debug Halt request or a debug breakpoint or trigger. Also, an MPC Debug Run request may only be signaled when the core is in Debug Mode due to either a previous MPC Debug Halt request, a previous Core Debug Halt request, or a debug breakpoint or trigger. Issuing more than one MPC Debug Halt requests in succession or more than one MPC Debug Run requests in succession is a protocol violation. ::: :::{list-table} Core Activity States :name: tab-core-activity-states :header-rows: 1 * - - **Active (C0)** - **Active (C0)** - **Sleep (C3)** * - - **Running** - **Halted** - **Halted** * - - - **db-halt** - **pmu/fw-halt** * - **State Description** - Core operating normally - Core halted in Debug Mode - Core halted by PMU halt request or by core firmware-initiated halt * - **Power Savings** - Fine-grain clock gating integrated in core minimizes power consumption during regular operation - Fine-grain clock gating - Enhanced clock gating in addition to fine-grain clock gating * - **DMA Access** - DMA accesses allowed - DMA accesses allowed - DMA accesses allowed * - **State Indication** - - `cpu_halt_status` is low - `debug_mode_status` is low (except for Core Debug Resume request with Single Step action) - - `cpu_halt_status` is low - `debug_mode_status` is high - - `cpu_halt_status` is high - `debug_mode_status` is low * - **Internal Timer Counters** - `mitcnt0/1` incremented every core clock cycle (also during execution of instructions while single-stepping in Debug Mode) - `mitcnt0/1` not incremented - Depends on *halt_en* bit in `mitctl0/1` registers: - 0: `mitcnt0/1` not incremented - 1: `mitcnt0/1` incremented every core clock cycle * - **Machine Cycle Performance- Monitoring Counter** - `mcycle` incremented every core clock cycle - Depends on *stopcount* bit of `dcsr` register (see [](debugging.md#debug-control-and-status-register-dcsr)): - 0: `mcycle` incremented every core clock cycle - 1: `mcycle` not incremented - `mcycle` not incremented ::: ## Power Control The priority order of simultaneous halt requests is as follows: 1. Any core debug halt action: * Core debug halt request * Core debug single step * Core debug breakpoint * Core debug trigger - or MPC debug halt request 2. PMU halt request or core firmware-initiated halt If the PMU sends a halt request while the core is in Debug Mode, the core disregards the halt request. If the PMU's halt request is still pending when the core exits Debug Mode, the request is honored at that time. Similarly, core firmware can't initiate a halt while in Debug Mode. However, it is not possible for a core firmware-initiated halt request to be pending when the core exits Debug Mode. :::{important} There are two separate sources of debug operations: the core itself which conforms to the standard RISC-V Debug specification [[3]](intro.md#ref-3), and the Multi-Processor Controller (MPC) IP block which provides multi-core debug capabilities. These two sources may interfere with each other and need to be carefully coordinated on a higher level outside the core. Unintended behavior might occur if simultaneous debug operations from these two sources are not synchronized (e.g., MPC requesting a resume during the execution of an abstract command initiated by the debugger attached to the JTAG port). ::: ### Debug Mode Debug Mode must be able to seize control of the core. Therefore, debug has higher priority than power control. Debug Mode is entered under any of the following conditions: * Core debug halt request * Core debug single step * Core debug breakpoint with halt action * Core debug trigger with halt action * Multi-core debug halt request (from MPC) Debug Mode is exited with: * Core debug resume request with no single step action * Multi-core debug run request (from MPC) The state 'db-halt' is the only halt state allowed while in Debug Mode. #### Single Stepping A few notes about executing single-stepped instructions: * Executing instructions which attempt to exit Debug Mode are ignored (e.g., writing to the `mpmc` register requesting to halt the core does not transition the core to the pmu/fw-halt state). * Accesses to D-mode registers are illegal, even though the core is in Debug Mode. * A core debug single-step action initiated in the time period between an MPC Debug Halt request and an MPC Debug Run request is stalled but stays pending until an MPC Debug Run request is issued. #### Forced Debug Halt Upon receiving a debug halt request (i.e., either a Core Debug or MPC Debug Halt request, or a breakpoint or trigger to Debug Mode), the core is typically quiesced before the Debug Halt (db-halt) state is entered. However, LSU or IFU bus transactions may not complete due to SoC or other issues outside the core which may stop the core from executing. This may prevent the core from entering the Debug Halt state after a debug halt request has been received. To enable a debugger taking control of the core, ongoing LSU and IFU bus transactions may be terminated after a programmable timeout period (see [](power.md#forced-debug-halt-threshold-register-mfdht)) has passed, forcing the core into the Debug Halt state. Once the debugger has control of the core, it may read a status register (see [](power.md#forced-debug-halt-status-register-mfdhs)) to inquire if LSU or IFU bus transactions have been terminated and data might have been lost. :::{note} This feature is targeted at allowing a debugger to take control of a hung core. Therefore, the timeout period should be set high enough to cover any reasonable delay incurred by any access to SoC memory locations and devices. This should include potential additional delays due to congestion in the interconnect and other possible temporary conditions. If the timeout period is long enough for all outstanding transactions to gracefully finish, program execution may be resumed after debugging has been performed. However, if any outstanding transactions are prematurely forced to terminate, successfully resuming program execution after debug should not be expected because the data of terminated transactions may have been lost and possibly even a reset of the SoC might be necessary to bring the system back into a consistent state. ::: ### Core Power and Multi-Core Debug Control and Status Signals {numref}`fig-debug-csrs` depicts the power and multi-core debug control and status signals which connect the VeeR EL2 core to the PMU and MPC IPs. Signals from the PMU and MPC to the core are asynchronous and must be synchronized to the core clock domain. Similarly, signals from the core are asynchronous to the PMU and MPC clock domains and must be synchronized to the PMU's or MPC's clock, respectively. :::{note} The synchronizer of the `cpu_run_req` signal may not be clock-gated. Otherwise, the core may not be woken up again via the PMU interface. ::: :::{figure-md} fig-debug-csrs ![Debug CSRS](img/debug_csrs.png) VeeR EL2 Power and Multi-Core Debug Control and Status Signals ::: #### Power Control and Status Signals There are three types of signals between the Power Management Unit and the VeeR EL2 core, as described in {numref}`tab-veer-el2-power-ctrl-status-signals`. All signals are active-high. :::{list-table} VeeR EL2 Power Control and Status Signals :name: tab-veer-el2-power-ctrl-status-signals * - **Signal(s)** - **Description** * - `cpu_halt_req` and `cpu_halt_ack` - Full handshake to request the core to halt. The PMU requests the core to halt (i.e., enter pmu/fw-halt) by asserting the `cpu_halt_req` signal. The core is quiesced before halting. The core then asserts the `cpu_halt_ack` signal. When the PMU detects the asserted `cpu_halt_ack` signal, it deasserts the `cpu_halt_req` signal. Finally, when the core detects the deasserted `cpu_halt_req` signal, it deasserts the `cpu_halt_ack` signal. **Note:** `cpu_halt_req` must be tied to '0' if PMU interface is not used. * - `cpu_run_req` and `cpu_run_ack` - Full handshake to request the core to run. The PMU requests the core to run by asserting the `cpu_run_req` signal. The core exits the halt state and starts execution again. The core then asserts the `cpu_run_ack` signal. When the PMU detects the asserted `cpu_run_ack` signal, it deasserts the `cpu_run_req` signal. Finally, when the core detects the deasserted `cpu_run_req` signal, it deasserts the `cpu_run_ack` signal. **Note:** `cpu_run_req` must be tied to '0' if PMU interface is not used. * - `cpu_halt_status` - Indication from the core to the PMU that the core has been gracefully halted. ::: :::{note} Power control protocol violations (e.g., simultaneously sending a run and a halt request) may lead to unexpected behavior. ::: {numref}`fig-csr-timing` depicts conceptual timing diagrams of a halt and a run request. Note that entering Debug Mode is an asynchronous event relative to power control commands sent by the PMU. Debug Mode has higher priority and can interrupt and override PMU requests. :::{figure-md} fig-csr-timing ![CSR Timing](img/csr_timing.png) VeeR EL2 Power Control and Status Interface Timing Diagrams ::: #### Multi-Core Debug Control and Status Signals There are five types of signals between the Multi-Processor Controller and the VeeR EL2 core, as described in {numref}`tab-veer-el2-multi-core-debug-ctrl-status-signals`. All signals are active-high. :::{list-table} VeeR EL2 Multi-Core Debug Control and Status Signals :name: tab-veer-el2-multi-core-debug-ctrl-status-signals * - **Signal(s)** - **Description** * - `mpc_debug_halt_req` and `mpc_debug_halt_ack` - Full handshake to request the core to debug halt. The MPC requests the core to halt (i.e., enter ‘db-halt’) by asserting the `mpc_debug_halt_req` signal. The core is quiesced before halting. The core then asserts the `mpc_debug_halt_ack` signal. When the MPC detects the asserted `mpc_debug_halt_ack` signal, it deasserts the `mpc_debug_halt_req` signal. Finally, when the core detects the deasserted `mpc_debug_halt_req` signal, it deasserts the `mpc_debug_halt_ack` signal. For as long as the `mpc_debug_halt_req` signal is asserted, the core must assert and hold the `mpc_debug_halt_ack` signal whether it was already in ‘db-halt’ or just transitioned into ‘db-halt’ state. **Note:** The *cause* field of the core’s `dcsr` register (see [](debugging.md#debug-control-and-status-register-dcsr)) is set to 3 (i.e., the same value as a debugger-requested entry to Debug Mode due to a Core Debug Halt request). Similarly, the `dpc` register (see [](debugging.md#debug-pc-register-dpc)) is updated with the address of the next instruction to be executed at the time that Debug Mode was entered. **Note:** Signaling more than one MPC Debug Halt request in succession is a protocol violation. **Note:** `mpc_debug_halt_req` must be tied to ‘0’ if MPC interface is not used. * - `mpc_debug_run_req` and `mpc_debug_run_ack` - Full handshake to request the core to run. The MPC requests the core to run by asserting the `mpc_debug_run_req` signal. The core exits the halt state and starts execution again. The core then asserts the `mpc_debug_run_ack` signal. When the MPC detects the asserted `mpc_debug_run_ack` signal, it deasserts the `mpc_debug_run_req` signal. Finally, when the core detects the deasserted `mpc_debug_run_req` signal, it deasserts the `mpc_debug_run_ack` signal. For as long as the `mpc_debug_run_req` signal is asserted, the core must assert and hold the `mpc_debug_run_ack` signal whether it was already in ‘Running’ or after transitioning into ‘Running’ state. **Note:** The core remains in the ‘db-halt’ state if a core debug request is also still active. **Note:** Signaling more than one MPC Debug Run request in succession is a protocol violation. **Note:** `mpc_debug_run_req` must be tied to ‘0’ if MPC interface is not used. * - `mpc_reset_run_req` - Core start state control out of reset: - 1: Normal Mode (‘Running’ or ‘pmu/fw-halt’ state) - 0: Debug Mode halted (‘db-halt’ state) **Note:** The core complex does not implement a synchronizer for this signal because the timing of the first clock is critical. It must be synchronized to the core clock domain outside the core in the SoC. **Note:** `mpc_reset_run_req` must be tied to ‘1’ if MPC interface is not used. * - `debug_mode_status` - Indication from the core to the MPC that it is currently transitioning to or already in Debug Mode. * - `debug_brkpt_status` - Indication from the core to the MPC that a software (i.e., ebreak instruction) or hardware (i.e., trigger hit) breakpoint has been triggered in the core. The breakpoint signal is only asserted for breakpoints and triggers with debug halt action. The signal is deasserted on exiting Debug Mode. ::: :::{note} Multi-core debug control protocol violations (e.g., simultaneously sending a run and a halt request) may lead to unexpected behavior. ::: :::{note} If the core is either not in the db-halt state (i.e., `debug_mode_status` indication is not asserted) or is already in the db-halt state due to a previous Core Debug Halt request or a debug breakpoint or trigger (i.e., `debug_mode_status` indication is already asserted), asserting the `mpc_debug_halt_req` signal is allowed and acknowledged with the assertion of the `mpc_debug_halt_ack` signal. Also, asserting the `mpc_debug_run_req` signal is only allowed if the core is in the db-halt state (i.e., `debug_mode_status` indication is asserted), but the core asserts the `mpc_debug_run_ack` signal only after the `cpu_run_req` signal on the PMU interface has been asserted as well, if a PMU Halt request was still pending. ::: :::{note} If the MPC is requesting the core to enter Debug Mode out of reset by activating the `mpc_reset_run_req` signal, the `mpc_debug_run_req` signal may not be asserted until the core is out of reset and has entered Debug Mode. Violating this rule may lead to unexpected core behavior. ::: :::{note} If Debug Mode is entered at reset by setting the `mpc_reset_run_req` signal to '0', only a run request issued on the `mpc_debug_run_req/ack` interface allows the core to exit Debug Mode. A core debug resume request issued by the debugger does not transition the core out of Debug Mode. ::: {numref}`fig-multicore-csr-timing` depicts conceptual timing diagrams of a halt and a run request. :::{figure-md} fig-multicore-csr-timing ![Multi-Core CSR Timing](img/multicore_csr_timing.png) VeeR EL2 Multi-Core Debug Control and Status Interface Timing Diagrams ::: {numref}`fig-breakpoint-timing` depicts conceptual timing diagrams of the breakpoint indication. :::{figure-md} fig-breakpoint-timing ![Breakpoint Indication Timing](img/breakpoint_timing.png) VeeR EL2 Breakpoint Indication Timing Diagrams ::: ### Debug Scenarios The following mixed core debug and MPC debug scenarios are supported by the core: #### Scenario 1: Core Halt → MPC Halt → MPC Run → Core Resume 1. Core debugger asserts a Debug Halt request which results in the core transitioning into Debug Halt state (db-halt). 2. In the system, another processor hits a breakpoint. The MPC signals a Debug Halt request to all processors to halt. 3. Core acknowledges this Debug Halt request as it is already in Debug Halt state (db-halt). 4. MPC signals a Debug Run request, but core is in the middle of a core debugger operation (e.g., an Abstract Command-based access) which requires it to remain in Debug Halt state. 5. Core completes debugger operation and waits for Core Debug Resume request from the core debugger. 6. When core debugger sends a Debug Resume request, the core then transitions to the Running state and deasserts the `debug_mode_status` signal. 7. Finally, core acknowledges MPC Debug Run request. #### Scenario 2: Core Halt → MPC Halt → Core Resume → MPC Run 1. Core debugger asserts a Debug Halt request which results in the core transitioning into Debug Halt state (db-halt). 2. In the system, another processor hits a breakpoint. The MPC signals Debug Halt request to all processors to halt. 3. Core acknowledges this Debug Halt request as it is already in Debug Halt state (db-halt). 4. Core debugger completes its operations and sends a Debug Resume request to the core. 5. Core remains in Halted state as MPC has not yet asserted its Debug Run request. The `debug_mode_status` signal remains asserted. 6. When MPC signals a Debug Run request, the core then transitions to the Running state and deasserts the `debug_mode_status` signal. 7. Finally, core acknowledges MPC Debug Run request. #### Scenario 3: Mpc Halt → Core Halt → Core Resume → Mpc Run 1. MPC asserts a Debug Halt request which results in the core transitioning into Debug Halt state (db-halt). 2. Core acknowledges this Debug Halt request. 3. Core debugger signals a Debug Halt request to the core. Core is already in Debug Halt state (db-halt). 4. Core debugger completes its operations and sends a Debug Resume request to the core. 5. Core remains in Halted state as MPC has not yet asserted its Debug Run request. The `debug_mode_status` signal remains asserted. 6. When MPC signals a Debug Run request, the core then transitions to the Running state and deasserts the `debug_mode_status` signal. 7. Finally, core acknowledges MPC Debug Run request. #### Scenario 4: MPC Halt → Core Halt → MPC Run → Core Resume 1. MPC asserts a Debug Halt request which results in the core transitioning into Debug Halt state (db-halt). 2. Core acknowledges this Debug Halt request. 3. Core debugger signals a Debug Halt request to the core. Core is already in Debug Halt state (db-halt). 4. MPC signals a Debug Run request, but core debugger operations are still in progress. Core remains in Halted state. The `debug_mode_status` signal remains asserted. 5. Core debugger completes operations and signals a Debug Resume request to the core. 6. The core then transitions to the Running state and deasserts the `debug_mode_status` signal. 7. Finally, core acknowledges MPC Debug Run request. #### Summary For the core to exit out of Debug Halt state (db-halt) in cases where it has received debug halt requests from both core debugger and MPC, it must receive debug run requests from both the core debugger as well as the MPC, irrespective of the order in which debug halt requests came from both sources. Until then, the core remains halted and the `debug_mode_status` signal remains asserted. ### Core Wake-Up Events When not in Debug Mode (i.e., the core is in pmu/fw-halt state), the core is woken up on several events: * PMU run request * Highest-priority external interrupt (`mhwakeup` signal from PIC) and core interrupts are enabled * Software interrupt * Timer interrupt * Internal timer interrupt * Non-maskable interrupt (NMI) (`nmi_int` signal) The PIC is part of the core logic and the `mhwakeup` signal is connected directly inside the core. The internal timers are part of the core and internally connected as well. The standard RISC-V software and timer interrupt as well as NMI signals are external to the core and originate in the SoC. If desired, these signals can be routed through the PMU and further qualified there. ### Core Firmware-Initiated Halt The firmware running on the core may also initiate a halt by writing a '1' to the *halt* field of the `mpmc` register (see [](power.md#power-management-control-register-mpmc)). The core is quiesced before indicating that it has gracefully halted. ### DMA Operations While Halted When the core is halted in the 'pmu/fw-halt' or the 'db-halt' state, DMA operations are supported. ### External Interrupts While Halted All non-highest-priority external interrupts are temporarily ignored while halted. Only external interrupts which activate the `mhwakeup` signal (see [](interrupts.md#regular-operation), Steps 13 and 14) are honored, if the core is enabled to service external interrupts (i.e., the *mie* bit of the `mstatus` and the *meie* bit of the `mie` standard RISC-V registers are both set, otherwise the core remains in the 'pmu/fw-halt' state). External interrupts which are still pending and have a sufficiently high priority to be signaled to the core are serviced once the core is back in the Running state. ## Control/Status Registers A summary of platform-specific control/status registers in CSR space: * [](power.md#power-management-control-register-mpmc) * [](power.md#core-pause-control-register-mcpc) * [](power.md#forced-debug-halt-threshold-register-mfdht) * [](power.md#forced-debug-halt-status-register-mfdhs) All reserved and unused bits in these control/status registers must be hardwired to '0'. Unless otherwise noted, all read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. ### Power Management Control Register (mpmc) The `mpmc` register provides core power management control functionality. It allows the firmware running on the core to initiate a transition to the Halted (pmu/fw-halt) state. While entering the Halted state, interrupts may optionally be enabled atomically. The *halt* field of the `mpmc` register has W1R0 (Write 1, Read 0) behavior, as also indicated in the 'Access' column. :::{note} Writing a '1' to the *haltie* field of the `mpmc` register without also setting the *halt* field has no immediate effect on the *mie* bit of the `mstatus` register. However, the *haltie* field of the `mpmc` register is updated accordingly. ::: :::{note} Once the *mie* bit of the `mstatus` register is set via the *haltie* field of the `mpmc` register, it remains set until other operations clear it. Exiting the Halted (pmu/fw-halt) state does not clear the *mie* bit of the `mstatus` register set by entering the Halted state. ::: :::{note} In Debug Mode, writing (i.e., setting or clearing) *haltie* has no effect on the `mstatus` register's *mie* bit since the core does not transition to the Halted (pmu/fw-halt) state. ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} Power Management Control Register (mpmc, at CSR 0x7C6) :name: tab-power-mgmt-ctrl-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:2 - Reserved - R - 0 * - haltie - 1 - Control interrupt enable (i.e., *mie* bit of `mstatus` register) when transitioning to Halted (pmu/fw-halt) state by setting halt bit below: - 0: Don't change *mie* bit of `mstatus` register - 1: Set *mie* bit of `mstatus` register (i.e., atomically enable interrupts) - R/W - 1 * - halt - 0 - Initiate core halt (i.e., transition to Halted (pmu/fw-halt) state) **Note:** Write ignored if in Debug Mode - R0/W1 - 0 ::: ### Core Pause Control Register (mcpc) The `mcpc` register supports functions to temporarily stop the core from executing instructions. This helps to save core power since busy-waiting loops can be avoided in the firmware. PAUSE stops the core from executing instructions for a specified number [^fn-power-1] of clock ticks or until an interrupt is received. [^fn-power-1]: The field width provided by the mcpc register allows to pause execution for about 4 seconds at a 1 GHz core clock. :::{note} PAUSE is a long-latency, interruptible instruction and does not change the core's activity state (i.e., the core remains in the Running state). Therefore, even though this function may reduce core power, it is not part of core power management. ::: :::{note} PAUSE has a skid of several cycles. Therefore, instruction execution might not be stopped for precisely the number of cycles specified in the *pause* field of the mcpc register. However, this is acceptable for the intended use case of this function. ::: :::{note} Depending on the *pause_en* bit of the `mitctl0/1` registers, the internal timers might be incremented while executing PAUSE. If an internal timer interrupt is signaled, PAUSE is terminated and normal execution resumes. ::: :::{note} If the PMU sends a halt request while PAUSE is still executing, the core enters the Halted (pmu/fw-halt) state and the *pause* clock counter stops until the core is back in the Running state. ::: :::{note} WFI is another candidate for a function that stops the core temporarily. Currently, the WFI instruction is implemented as NOP, which is a fully RISC-V-compliant option. ::: The *pause* field of the `mcpc` register has WAR0 (Write Any value, Read 0) behavior, as also indicated in the 'Access' column. This register is mapped to the non-standard read/write CSR address space. :::{list-table} Core Pause Control Register (mcpc, at CSR 0x7C2) :name: tab-core-pause-ctrl-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - pause - 31:0 - Pause execution for number of core clock cycles specified **Note:** *pause* is decremented by 1 for each core clock cycle. Execution continues either when *pause* is 0 or any interrupt is received. - R0/W - 0 ::: ### Forced Debug Halt Threshold Register (mfdht) The `mfdht` register hosts the enable bit of the forced debug halt mechanism as well as the power-of-two exponent of the timeout threshold. When enabled, if a debug halt request is received and LSU and/or IFU bus transactions are pending, an internal timeout counter starts incrementing with each core clock and keeps incrementing until the Debug Halt *(db-halt)* state is entered. If all ongoing bus transactions complete within the timeout period and the core is quiesced, the Debug Halt state is entered as usual. However, if the timeout counter *value* is equal to or greater than the threshold value (= {math}`2^{thresh}` core clocks), all in-progress LSU and IFU bus transactions are terminated and the Debug Halt state is entered (i.e. the core may be forced to the Debug Halt state before it is fully quiesced). In addition, when entering the Debug Halt state in either case, the `mfdhs` register (see [](power.md#forced-debug-halt-status-register-mfdhs) below) latches the status if any LSU or IFU bus transactions have been prematurely terminated. :::{note} The internal timeout counter is cleared at reset as well as when the Debug Halt (db-halt) state is exited. ::: :::{note} The 5-bit threshold (*thresh* field) allows a timeout period of up to {math}`2^{31}` core clock cycles (i.e., about 2.1 seconds at a 1GHz core clock frequency). ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} Forced Debug Halt Threshold Register (mfdht, at CSR 0x7CE) :name: tab-forced-debug-halt-thld-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:6 - Reserved - R - 0 * - thresh - 5:1 - Power-of-two exponent of timeout threshold (= {math}`2^{thresh}` core clock cycles) - R/W - 0 * - enable - 0 - Enable/disable forced debug halt timeout: - 0: Timeout mechanism disabled (default) - 1: Timeout mechanism enabled - R/W - 0 ::: ### Forced Debug Halt Status Register (mfdhs) The mfdhs register provides status information if any LSU and/or IFU bus transactions have been prematurely terminated when the Debug Halt (db-halt) state has been entered. A debugger may read this register to inquire if any bus transactions have been terminated and data may have been lost while entering the Debug Halt state. If both status bits are '0' indicates that the core was properly quiesced. :::{note} A debugger may also clear the status bits if desired, but clearing is not required for proper operation. ::: This register is mapped to the non-standard read/write CSR address space. :::{list-table} Forced Debug Halt Status Register (mfdhs, at CSR 0x7CF) :name: tab-forced-debug-halt-status-register * - **Field** - **Bits** - **Description** - **Access** - **Reset** * - Reserved - 31:2 - Reserved - R - 0 * - lsu - 1 - LSU bus transaction termination status: - 0: No transactions have been prematurely terminated - 1: One or more transactions have been prematurely terminated - R/W - 0 * - ifu - 0 - IFU bus transaction termination status: - 0: No transactions have been prematurely terminated - 1: One or more transactions have been prematurely terminated - R/W - 0 ::: ================================================ FILE: docs/source/simulation-debugging.md ================================================ # Interactive Debugging in Simulation It is possible to perform a debugging session through a virtual JTAG interface with the VeeR EL2 Core running in simulation. This allows the user to exercise JTAG usage scenarios using actual debugging tools instead of unit tests written for JTAG logic. The feature was added to the VeeR EL2 Core with [Pull Request #211](https://github.com/chipsalliance/Cores-VeeR-EL2/pull/211). The principle of operation is a JTAG probe RTL model which communicates with the host via DPI. This is illustrated in {numref}`fig-openocd-jtag`: :::{figure-md} fig-openocd-jtag ![](img/openocd-jtag.png) OpenOCD JTAG ::: Currently the probe model implements the `remote_bitbang` protocol of [OpenOCD](https://openocd.org/), allowing the tool to interact with simulation. The protocol operates over a TCP/IP connection or a UNIX socket. An appropriate server and protocol decoder runs on the host machine and communicates with the simulation via DPI to set/read JTAG signal states. The entire flow is transparent to the debugging tools and to the user. The probe model has been integrated into the testbench. It is active every time the testbench is run; there is no need for any additional action. To run a testbench, execute, for example: ```bash make -C run -f ${RV_ROOT}/tools/Makefile verilator-build program.hex TEST=infinite_loop \ CONF_PARAMS="-set openocd_test" ``` The `RV_ROOT` variable in the snippet above is the path to the root of the Cores-VeeR-EL2 repository. To keep the simulation running continuously, the `infinite_loop` test program has been added. The program consists of two nested loops running continuously. Then, to connect to a running simulation via OpenOCD, you can use the configs available in the `testbench/openocd_scripts` directory: ```bash cd testbench/openocd_scripts openocd -d2 -f verilator-rst.cfg jtag_cg.tcl ``` `jtag_cg.ctl` is an OpenOCD script that performs JTAG access tests. These include core register access and memory access. The configuration is passed by `verilator-rst.cfg`. It includes `sim-jtagdpi.cfg` and `veer-el2-rst.cfg`. `sim-jtagdpi.cfg` contains a JTAG adapter configuration. `veer-el2-rst.cfg` configures the target for OpenOCD. The test involves the CPU core held permanently in reset. Moreover, a [customized version of OpenOCD](https://github.com/antmicro/openocd/tree/riscv-nohalt) had to be used, as the stock version performs target CPU examination by default which is not possible when in reset. ### Automation In the `.github/scripts` directory of the [VeeR](https://github.com/chipsalliance/Cores-VeeR-EL2) repository, you can find a helper `openocd_test.sh` script that is responsible for launching simulation, executing an OpenOCD script as a test and terminating it. The script is used in CI. The script assumes that both the verilated simulation and the CPU program binary are already built. You can find a usage example in the GitHub Action workflow definition: `.github/workflows/test-openocd.yml`. ================================================ FILE: docs/source/tests.md ================================================ # Compliance Test Suite Failures ## *I-MISALIGN_LDST-01* * **Test Location**: [https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32i/src/I-MISALIGN_LDST-01.S](https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32i/src/I-MISALIGN_LDST-01.S) * **Reason for Failure**: * The VeeR EL2 core supports unaligned accesses to memory addresses which are not marked as having side effects (i.e., to idempotent memory). Load and store accesses to non-idempotent memory addresses take misalignment exceptions. * Note that this is a known issue with the test suite ([https://github.com/riscv/riscv-compliance/issues/22](https://github.com/riscv/riscv-compliance/issues/22)) and is expected to eventually be fixed. * **Workaround**: * Configure the address range used by this test to "non-idempotent" in the `mrac` register. ## *I-MISALIGN_JMP-01* * **Test location**: [https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32i/src/I-MISALIGN_JMP-01.S](https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32i/src/I-MISALIGN_JMP-01.S) * **Reason for Failure**: * The VeeR EL2 core supports the standard "C" 16-bit compressed instruction extension. Compressed instruction execution cannot be turned off. Therefore, branch and jump instructions to 16-bit aligned memory addresses do not trigger misalignment exceptions. * Note that this is a known issue with the test suite ([https://github.com/riscv/riscv-compliance/issues/16](https://github.com/riscv/riscv-compliance/issues/16)) and is expected to eventually be fixed. * **Workaround**: * None. ## *I-FENCE.I-01 and fence_i* * **Test location**: * [https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32Zifencei/src/I-FENCE.I-01.S](https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32Zifencei/src/I-FENCE.I-01.S) and * [https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32ui/src/fence_i.S](https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32ui/src/fence_i.S) * **Reason for Failure**: * The VeeR EL2 core implements separate instruction and data buses to the system interconnect (i.e., Harvard architecture). The latencies to memory through the system interconnect may be different for the two interfaces and the order is therefore not guaranteed. * **Workaround**: * Configuring the address range used by this test to "non-idempotent" in the `mrac` register forces the core to wait for a write response before fetching the updated line. Alternatively, the system interconnect could provide ordering guarantees between requests sent to the instruction fetch and load/store bus interfaces (e.g., matching latencies through the interconnect). ## *Breakpoint* * **Test Location**: * [https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32mi/src/breakpoint.S](https://github.com/riscv/riscv-compliance/blob/master/riscv-test-suite/rv32mi/src/breakpoint.S) * **Reason for Failure**: * The VeeR EL2 core disables breakpoints when the *mie* bit in the standard `mstatus` register is cleared. * Note that this behavior is compliant with the RISC-V External Debug Support specification, Version 0.13.2. See Section 5.1, 'Native M-Mode Triggers' in [[3]](intro.md#ref-3) for more details. * **Workaround**: * None. ================================================ FILE: docs/source/timers.md ================================================ # Internal Timers This chapter describes the internal timer feature of the VeeR EL2 core. ## Features The VeeR EL2's internal timer features are: * Two independently controlled 32-bit timers * Dedicated counter * Dedicated bound * Dedicated control to enable/disable incrementing generally, during power management Sleep, and while executing PAUSE * Enable/disable local interrupts (in standard RISC-V `mie` register) * Cascade mode to form a single 64-bit timer ## Description The VeeR EL2 core implements two internal timers. The `mitcnt0` and `mitcnt1` registers (see [Internal Timer Counter 0 / 1 Register (mitcnt0/1)](timers.md#internal-timer-counter-0-1-register-mitcnt0-1)) are 32-bit unsigned counters. Each counter also has a corresponding 32-bit unsigned bound register (i.e., `mitb0` and `mitb1`, see [Internal Timer Bound 0 / 1 Register (mitb0/1)](timers.md#internal-timer-bound-0-1-register-mitb0-1)) and control register (i.e., `mitctl0` and `mitctl1`, see [Internal Timer Control 0 / 1 Register (mitctl0/1)](timers.md#internal-timer-control-0-1-register-mitctl0-1)). All registers are cleared at reset unless otherwise noted. After reset, the counters start incrementing the next clock cycle if the increment conditions are met. All registers can be read as well as written at any time. The `mitcnt0/1` and `mitb0/1` registers may be written to any 32-bit value. If the conditions to increment are met, the corresponding counter `mitcnt0/1` increments every clock cycle. Cascade mode (see [Internal Timer Control 0 / 1 Register (mitctl0/1)](timers.md#internal-timer-control-0-1-register-mitctl0-1)) links the two counters together. The `mitcnt1` register is only incremented when the conditions to increment `mitcnt1` are met and the `mitcnt0` register is greater than or equal to the bound in its `mitb0` register. For each timer, a local interrupt (see [](timers.md#internal-timer-local-interrupts)) is triggered when that counter is at or above its bound. When a counter is at or above its bound, it gets cleared the next clock cycle (i.e., the interrupt condition is not sticky). :::{note} If the core is in Debug Mode and being single-stepped, it may take multiple clock cycles to execute a single instruction. If the conditions to increment are met, the counter increments for every clock cycle it takes to execute a single instruction. Therefore, every executed single-stepped instruction in Debug Mode may result in multiple counter increments. ::: :::{note} If the core is in the Debug Mode's Halted (i.e., db-halt) state, an internal timer interrupt does not transition the core back to the Active (i.e., Running) state. ::: ## Internal Timer Local Interrupts Local-to-the-core interrupts for internal timer 0 and 1 have pending [^fn-timers-1] (*mitip0/1*) and enable (*mitie0/1*) bits in bit positions 29 (for internal timer 0) and 28 (for internal timer 1) of the standard RISC-V `mip` (see {numref}`tab-machine-interrupt-pending-register`) and `mie` (see {numref}`tab-machine-interrupt-enable-register`) registers, respectively. The priority is lower than the RISC-V External, Software, and Timer interrupts (see {numref}`tab-veer-el2-platform-specific-and-std-risc-v-interrupt-priorities`). The internal timer 0 and 1 local interrupts have an mcause value of 0x8000_001D (for internal timer 0) and 0x8000_001C (for internal timer 1) (see {numref}`tab-machine-cause-register`). :::{note} If both internal timer interrupts occur in the same cycle, internal timer 0's interrupt has higher priority than internal timer 1's interrupt. ::: :::{note} A common interrupt service routine may be used for both interrupts. The `mcause` register value differentiates the two local interrupts. ::: [^fn-timers-1]: Since internal timer interrupts are not latched (i.e., not “sticky”) and these local interrupts are only signaled for one core clock cycle, it is unlikely that they are detected by firmware in the `mip` register. ## Control/Status Registers A summary of platform-specific internal timer control/status registers in CSR space: - [Internal Timer Counter 0 / 1 Register (mitcnt0/1)](timers.md#internal-timer-counter-0-1-register-mitcnt0-1) - [Internal Timer Bound 0 / 1 Register (mitb0/1)](timers.md#internal-timer-bound-0-1-register-mitb0-1) - [Internal Timer Control 0 / 1 Register (mitctl0/1)](timers.md#internal-timer-control-0-1-register-mitctl0-1) All reserved and unused bits in these control/status registers must be hardwired to '0'. Unless otherwise noted, all read/write control/status registers must have WARL (Write Any value, Read Legal value) behavior. ### Internal Timer Counter 0 / 1 Register (mitcnt0/1) The `mitcnt0` and `mitcnt1` registers are the counters of the internal timer 0 and 1, respectively. The conditions to increment a counter are: - The *enable* bit in the corresponding mitctl0/1 register is '1', - if the core is in Sleep (i.e., pmu/fw-halt) state, the *halt_en* bit in the corresponding `mitctl0/1` register is '1', - if the core is paused, the *pause_en* bit in the corresponding `mitctl0/1` register is '1', and - the core is not in Debug Mode, except while executing a single-stepped instruction. A counter is cleared if its value is greater than or equal to its corresponding mitb0/1 register. :::{note} If a write to the `mitcnt0/1` register is committed in the same clock cycle as the timer interrupt condition is met, the internal timer local interrupt is triggered, if enabled, but the counter is not cleared in this case. Instead, the counter is set to the written value. ::: These registers are mapped to the non-standard read/write CSR address space. :::{list-table} Internal Timer Counter 0 / 1 Register (mitcnt0/1, at CSR 0x7D2 / 0x7D5) :name: tab-internal-timer-counter-register :header-rows: 1 :align: left * - Field - Bits - Description - Access - Reset * - count - 31:0 - Counter - R/W - 0 ::: ### Internal Timer Bound 0 / 1 Register (mitb0/1) The `mitb0` and `mitb1` registers hold the upper bounds of the internal timer 0 and 1, respectively. These registers are mapped to the non-standard read/write CSR address space. :::{list-table} Internal Timer Bound 0 / 1 Register (mitb0/1, at CSR 0x7D3 / 0x7D6) :name: tab-internal-timer-bound-register :header-rows: 1 :align: left * - Field - Bits - Description - Access - Reset * - bound - 31:0 - Bound - R/W - 0xFFFF_FFFF ::: ### Internal Timer Control 0 / 1 Register (mitctl0/1) The `mitctl0` and `mitctl1` registers provide the control bits of the internal timer 0 and 1, respectively. :::{note} When in cascade mode, it is highly recommended to program the enable, *halt_en*, and *pause_en* control bits of the `mitctl1` register the same as the `mitctl0` register. ::: These registers are mapped to the non-standard read/write CSR address space. :::{list-table} Internal Timer Control 0 / 1 Register (mitctl0/1, at CSR 0x7D4 / 0x7D7) :name: tab-internal-timer-control-register :header-rows: 1 :align: left * - Field - Bits - Description - Access - Reset * - Reserved - 31:4 - Reserved - R - 0 * - cascade **(mitctl1 only)** - 3 - Cascade mode: - 0: Disable cascading (i.e., both internal timers operate independently) (default) - 1: Enable cascading (i.e., internal timer 0 and 1 are combined into a single 64-bit timer) - R/W - 0 * - pause_en - 2 - Enable/disable incrementing timer counter while executing PAUSE: - 0: Disable incrementing (default) - 1: Enable incrementing **Note:** If ‘1’ and the core is pausing (see [](power.md#core-pause-control-register-mcpc)), an internal timer interrupt terminates PAUSE and regular execution is resumed. - R/W - 0 * - halt_en - 1 - Enable/disable incrementing timer counter while in Sleep (i.e., pmu/fw- halt) state: - 0: Disable incrementing (default) - 1: Enable incrementing **Note:** If ‘1’ and the core is in Sleep (i.e., pmu/fw-halt) state, an internal timer interrupt transitions the core back to the Active (i.e., Running) state and regular execution is resumed. - R/W - 0 * - enable - 0 - Enable/disable incrementing timer counter: - 0: Disable incrementing - 1: Enable incrementing (default) - R/W - 1 ::: ================================================ FILE: docs/source/tock.md ================================================ # Running Tock OS This chapter describes the steps necessary to build a [Tock OS](https://github.com/tock/tock) application for the VeeR EL2 core, along with instructions for running it in simulation using [Verilator](https://github.com/verilator/verilator). ## Prerequisites Install build dependencies: ``` apt install curl make build-essential gcc-riscv64-unknown-elf wget unzip python3-pip ``` To compile Tock, you need a Rust toolchain installer called `rustup`: ``` curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` For detailed information on installing Tock OS, refer to the project's [documentation](https://book.tockos.org/). ## Fetching sources ``` git clone https://github.com/tock/tock.git cd tock ``` ## Running simulation in Verilator In order to compile Tock OS and start simulation, run: ``` make -C boards/veer_el2_sim sim ``` The expected output is: ``` VerilatorTB: Start of sim mem_signature_begin = 00000000 mem_signature_end = 00000000 mem_mailbox = D0580000 VeeR EL2 initialisation complete. Entering main loop. ``` ## Running simulation in Verilator with applications ### Building Tock In order to compile Tock, run: ``` make -C boards/veer_el2_sim ``` ### Building an application ``` git clone https://github.com/tock/libtock-c.git make -C libtock-c/examples/c_hello -j$(nproc) ``` ### Providing a verilog file for simulation The testbench for Verilator requires a single file with a program (`program.hex`), so it's necessary to combine the kernel and applications into a single binary first. You can use Tockloader to create a binary file representing flash with the kernel, and then install the application: ``` tockloader flash --board veer_el2_sim --flash-file ./veer_el2_sim.bin --address 0x20000000 ./target/riscv32imc-unknown-none-elf/release/veer_el2_sim.bin tockloader install --board veer_el2_sim --arch rv32imc --flash-file ./veer_el2_sim.bin libtock-c/examples/c_hello/build/c_hello.tab riscv64-unknown-elf-objcopy --change-addresses 0x20000000 -I binary -O verilog veer_el2_sim.bin program.hex ``` Now `program.hex` is ready for use in simulation. ### Starting simulation in Verilator Clone the Cores-VeeR-EL2 repository: ``` git clone https://github.com/chipsalliance/Cores-VeeR-EL2.git cd Cores-VeeR-EL2 git switch --detach da1042557 ``` Increase the maximum number of cycles in simulation: ``` sed -i 's/parameter MAX_CYCLES = 2_000_000;/parameter MAX_CYCLES = 10_000_000;/g' testbench/tb_top.sv ``` You can build a testbench using these commands: ``` export RV_ROOT=$(pwd) make -C tools CONF_PARAMS='-set build-axi4 -set user_mode=1 -set reset_vec=0x20000000' verilator-build ``` Make sure the program you want to run is placed in the current working directory and named `program.hex`: ``` cp ../program.hex . ``` In order to start the simulation, run: ``` ./tools/obj_dir/Vtb_top ``` The output should look like this: ``` VerilatorTB: Start of sim mem_signature_begin = 00000000 mem_signature_end = 00000000 mem_mailbox = D0580000 VeeR EL2 initialisation complete. Entering main loop. Hello World! ``` The execution trace will be located in `exec.log`. ================================================ FILE: docs/source/user-mode.md ================================================ # User Mode Originally, VeeR EL2 only implemented machine mode, and user mode support was added for the Caliptra project. By default the VeeR EL2 Core is configured in machine mode only, so to enable user mode, use the `-set` option in [the config script](../../configs/veer.config): ``` veer.config -set=user_mode=1 ``` With this option enabled, the *RV_USER_MODE* macro is defined. All code related to user mode is guarded by *ifdef RV_USER_MODE* / *endif* blocks. ## Machine ISA Register (misa) The read-only `misa` register provides information about features and instruction sets supported by the core. In the user mode configuration, the U bit (20) is set. ## Machine Status Register (mstatus) The `mstatus` register is extended with the following fields: - *MPP* - 2-bit wide field - stores the previous core operating mode after entering an exception handler. It is implemented with a single FF (permissible if supervisor mode is not present in the design). The FF stores an inverted value, so that upon core reset, the field indicates machine mode (*2'b11*) - *MPEV* - allows temporarily changing the effective privilege mode for load and store instructions ## Machine Environment Configuration Registers (menvcfg,menvcfgh) The `menvcfg` and `menvcfgh` registers control the behavior of *FENCE* instruction flavors and contain bits relevant to the Sstc, Zicboz and Zicbom extensions. None of these extensions are supported by the VeeR EL2 core and the core is in-order, so this register pair is read-only and all-zero. ## User Mode Performance Counters (cycle, cycleh, instret, instreth) In order to enable performance monitoring in user mode, unprivileged shadow copies of `mcycle` and `minstret` registers are implemented: `cycle` and `instret`. These are read-only registers accessible from user mode. Access to the shadow copies can be restricted by the `mcounteren` CSR. The `cycleh` and `instreth` registers are upper 32-bits of the `cycle` and `instret` registers, respectively. ## Machine Counter-Enable Register (mcounteren) The `mcounteren` register controls access to the user mode shadow copies of the performance counters. Only software running in machine mode can change the `mcounteren` register, so that it can grant/deny permission to specific counters for user mode applications. ## Machine Security Configuration Register (mseccfg, mseccfgh) The `mseccfg` and `mseccfgh` registers control PMP's behavior when Smepmp is enabled. The *RLB*, *MMWP* and *MML* bits are implemented, whereas others are read-only zero. ## Privilege Mode Transitions and Exception Handling The VeeR EL2 core only implements machine and user mode, so only 2 mode transitions are possible: - When `mret` is executed, the operating mode is changed to the value of the *mstatus.MPP* field. - When an exception is entered, the core enters machine mode. When the core enters a trap, it immediately switches mode to machine and the pipeline is flushed. The introduction of user mode adds 2 new *mcause* codes for a trap caused by the *ECALL* instruction: - 11 (0xb) for *ECALL.M*, if ECALL is executed in machine mode - 8 (0x8) for *ECALL.U*, if ECALL is executed in user mode ## PMP Enhancements for Memory Access and Execution Prevention on Machine Mode Document [[6]](intro.md#ref-6) defines an extension to PMP's behavior. Smepmp (extended PMP) support is enabled with the `-set=smepmp=1` option: ``` veer.config -set=user_mode=1 -set=smepmp=1 ``` When the flag is set, the *RV_SMEPMP* macro is defined. The Smepmp extension can only be used together with the user mode configuration. ================================================ FILE: docs/source/verification.md ================================================ # Verification This chapter documents verification of the VeeR EL2 Core and coverage data collection, including RTL-level tests designed to exercise parts of the core's logic, software execution tests, randomized code generator tests, as well as verification coverage. Tests listed in this chapter are run in [Continuous Integration pipelines](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/.github/workflows) of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2) via GitHub Actions. ## RTL-level tests Verification of the VeeR EL2 Core includes an RTL test suite created to exercise details of the core's internal architecture. These tests complement the software execution tests described in [later section of this chapter](#software-execution-tests). RTL-level tests include block-level as well as top-level tests developed for the VeeR EL2 Core: * Block-level tests are located in the [`verification/block` directory](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/verification/block) of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2). * Top-level tests are located in the [`verification/top` directory](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/verification/top) of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2). ### Cocotb tests The main group of RTL tests were implemented using [cocotb](https://www.cocotb.org/), a popular co-simulation testbench library for Python, allowing for re-use of the extensive Python testing ecosystem for design verification. The test files are located in the [`verification/block/`](https://github.com/chipsalliance/Cores-VeeR-EL2/blob/main/verification/block/) directory of the [`Cores-VeeR-EL2 repository`](https://github.com/chipsalliance/Cores-VeeR-EL2/). The verification environment is extended by a PyUVM (Universal Verification Methodology implemented in Python instead of SystemVerilog) test with a corresponding CI workflow. It implements a basic PyUVM structure to test the core's behavior when interrupt pins are stimulated. ### UVM verification UVM tests are run as the `Test-UVM` job in the CI pipelines of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2). The test files are located in the [`testbench/uvm` directory](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/testbench/uvm) of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2). ## Software execution tests ### Regression tests Regression tests are run as the `Test-Regression` job in the CI pipelines of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2). Regression testing involves execution of rudimentary software that was executed correctly on previous runs. The regression test executes `.hex` files of the following pieces of software: * A `hello_world` program * A Dhrystone benchmark program * A Coremark benchmark program Regression tests include verification of privilege mode switching. The test files are located in the [`testbench/tests/modesw` directory](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/testbench/tests/modesw) of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2) and described in more detail in the [README file](https://github.com/chipsalliance/Cores-VeeR-EL2/blob/main/testbench/tests/modesw/README.md). ### Renode tests [Renode](https://renode.io/) is a deterministic simulation framework used to verify proper software execution. The tests are defined in the [`testbench/tests` directory](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/testbench/tests) of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2). Renode uses [Robot Framework](https://robotframework.org/), an open source automation framework for test automation and robotic process automation (RPA). A testing script to execute test binaries is defined in the [`veer.robot` file](https://github.com/chipsalliance/Cores-VeeR-EL2/blob/main/tools/renode/veer.robot). For detailed information regarding verification of the VeeR EL2 core with Renode, refer to the [VeeR EL2 Support in Renode README](https://github.com/chipsalliance/Cores-VeeR-EL2/blob/main/tools/renode/README.md). ### RISCOF Verification [RISCOF](https://riscof.readthedocs.io/en/stable/index.html) is a RISC-V core test framework. It uses [official architectural assembly test programs](https://github.com/riscv-non-isa/riscv-arch-test) where the core memory state is compared against a reference. The comparison happens between the simulated core under test and a reference ISS, similar to [tests with RISCV-DV](#riscv-dv-verification) described below. The RISCOF framework exercises the VeeR core with tests that use the Spike ISS and Verilator. Like with RISCV-DV, a mismatch in memory signature comparison is reported as a CI failure. The compared memory region is known as the memory signature. Its boundaries are defined by special symbols defined in each test program. It is the responsibility of the simulator / ISS to dump the memory signature for comparison by RISCOF. For more detailed information about verification of the VeeR EL2 core with RISCOF, refer to the [README](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/tools/riscof). #### Adaptation of VeeR simulation and testbench to RISCOF Adaptation of VeeR for RISCOF required implementing the memory signature dump. Thanks to the use of Verilator it was possible to automatically load and parse the symbol map extracted from the binary ELF file and inject signature boundary addresses to the RTL simulation. The simulation executable accepts the `--symbols` argument which specifies the symbol map file obtained using the `nm` utility. The addresses can also be provided manually via the `--mem-signature` argument as two hexadecimal numbers. The memory dump itself is implemented as a SystemVerilog task called from the RTL code right before the simulation ends. The output file name is fixed to `veer.signature`. The task automatically assures access to the correct memory - data is loaded from DCCM by default. Otherwise, it is taken from the generic RAM present in the testbench. When no signature range is defined, the dump is not written. #### RISCOF model plugin RISCOF uses Python plugins to interface with simulated cores and ISSs. The task of a plugin is to build and link assembly test programs in a way suitable for core / ISS use and to run the simulation. The plugin may also provide dedicated code snippets used by test programs to communicate with the simulation (eg. signal program end). Currently plugins are available for the Spike ISS and the SAIL ISS. Since every RTL simulation framework for a core is different, it requires a dedicated plugin. The VeeR plugin, located in the [`/tools/riscof/veer`](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/tools/riscof/veer) directory of this repository, performs the following tasks: * Code compilation and linking * Symbol dump (to get the memory signature address range) * Simulation run * Result collection (moving / renaming the output memory signature dump file) The VeeR RTL needs to be "Verilated" upfront as the plugin assumes that the simulation binary is already present. ## RISCV-DV verification [RISCV-DV](https://github.com/chipsalliance/riscv-dv) is a verification framework (originally from Google, now also in CHIPS Alliance) designed to test and (co-)verify RISC-V CPU cores. RISCV-DV tests are run as the `Test-RISCV-DV` job in the CI pipelines of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2). Pre-generated RISCV-DV test programs for fallback in case of failure in generation in CI pipelines are stored in the [`.github/assets/riscv-dv` directory](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/.github/assets/riscv_dv). The framework generates random instruction chains to exercise certain core features and relies on the [Universal Verification Methodology (UVM)](https://www.accellera.org/community/uvm) for code generation. These instructions are then simultaneously executed by the core (RTL simulation) and by a reference RISC-V ISS (instruction set simulator), for example [Spike](https://github.com/riscv-software-src/riscv-isa-sim). The core states of both are then compared and an error is reported in case of a mismatch. RISCV-DV tests are run as the `Test-RISCV-DV` job in the CI pipelines of the [`cores-veer-el2` repository](https://github.com/chipsalliance/Cores-VeeR-EL2). This job is responsible for running the RISCV-DV test suite on the VeeR core, downloading Renode and building the VeeR ISS. A mismatch between an ISS trace and the RTL trace reported by RISCV-DV framework immediately triggers a CI error. ### RISCV-DV Test flow The RISCV-DV test flow for the VeeR EL2 Core looks as follows: * Generate a program using a `RISCV-DV` generator * Run the program in a RISC-V ISS, collect the trace * Run the program inside a simulation of the VeeR EL2 core using [Verilator](https://www.veripool.org/verilator/) and collect the trace * Compare both execution trace files * If no mismatches are found, the test is successful {numref}`riscv-dv-flow` below illustrates this flow. :::{figure-md} riscv-dv-flow ![riscv-dv-flow](img/riscv-dv-flow.png) RISCV-DV flow ::: For more detailed information about verification of the VeeR EL2 core with RISCV-DV, refer to the [README](https://github.com/chipsalliance/Cores-VeeR-EL2/tree/main/tools/riscv-dv). In a physical design, external stimulus, e.g. from interrupt source or debugging requests, causes relevant CSRs to be updated automatically, which is not always the case for tests relying solely on generated streams of instructions. In the future, tests to verify these features will be implemented using the [RISCV-DV handshaking mechanism](https://github.com/chipsalliance/riscv-dv/blob/master/docs/source/handshake.rst), a feature put in place specifically to update the core's internal state properly. ### Current implementation Since RISCV-DV does not provide a generic way of simulating RISC-V cores at RTL level, this implementation runs the existing testbench for VeeR EL2 in Verilator. RISCV-DV requires execution traces in its own standardized format, so we developed a Python script which parses the VeeR EL2 execution log and converts it to the [CSV format](https://htmlpreview.github.io/?https://github.com/google/riscv-dv/blob/master/docs/build/singlehtml/index.html#trace-csv-format) accepted by RISCV-DV. The end-to-end flow is implemented by the Makefile in `tools/riscv-dv`. The RISCV-DV `run.py` script is used for random code generation, compilation and ISS execution. A set of Makefile rules implements building the verilated testbench, running it, converting trace logs and trace comparison. The comparison itself is done by `instr_trace_compare.py` in RISCV-DV. The flow currently supports three ISSs: * [Spike](https://github.com/riscv-software-src/riscv-isa-sim) * [Renode](https://renode.io/) The CI workflow for RISCV-DV builds or downloads the prerequisites (Verilator, Spike, Renode) and invokes the test flow. A failure of any of RISCV-DV tests is reported as CI failure. ### Renode integration [Renode](https://renode.io/) is Antmicro's open source development framework which allows debugging and testing unmodified embedded software on your PC - from bare System-on-Chips, through complete devices, to multi-node systems. As a part of the the project, we extended the RISCV-DV framework [with Renode ISS support](https://github.com/chipsalliance/riscv-dv/pull/935). The work also included defining a virtual Renode platform for VeeR EL2, executing RISCV-DV pseudo-random programs on it and collecting execution trace logs. Basic level VeeR EL2 support in Renode opens up the potential to simulate the Caliptra RoT as well as the RoT in the context of a larger SoC in conjunction with Renode's support for e.g. ARM and RISC-V cores and peripherals or OpenTitan peripherals (some of which are used in Caliptra) ## Verification coverage For each of the tests described in this chapter, data is collected and processed to determine verification coverage. ### Coverage analysis To verify whether all parts of a design have been tested, you can get coverage reports from simulation runs which inform about a percentage of possible design states that were simulated. You can then use this information to prepare new testing scenarios that test previously untested design states. Results for verification coverage of the entire design as well as its parts are available in the [VeeR EL2 coverage dashboard](https://chipsalliance.github.io/Cores-VeeR-EL2/html/main.html). The results are updated with each Pull Request, as visible in the [Active pull request list](https://chipsalliance.github.io/Cores-VeeR-EL2/html/dev.html). Data is only available for open Pull Requests and is removed once a Pull Request is closed or merged. ### Coverage analysis with open source tools Verilator supports certain method of test [coverage analysis](https://veripool.org/guide/latest/simulating.html#coverage-analysis). There are three ways in which Verilator collects coverage data: * Line coverage Verilator automatically counts changes to the RTL code flow at all possible branch points. * Toggle coverage Automatic toggle count for each signal. Does not apply to certain signal types as described in [Verilator's documentation](https://veripool.org/guide/latest/simulating.html#coverage-analysis). * Functional coverage Verilator automatically counts events defined by the `cover property`, which are implemented in the source code. To enable coverage collection with Verilator, simply add the following lines to the C++ testbench: ``` // Write coverage data #if VM_COVERAGE Verilated::threadContextp()->coveragep()->write("coverage.dat"); #endif ``` The `genhtml` utility from the `lcov` package is used to convert the data collected from the verification into `.html` files present it in the form of [the VeeR EL2 coverage dashboard](https://chipsalliance.github.io/Cores-VeeR-EL2/html/main/coverage_dashboard/all/index.html). ### Identification of signals without coverage The recommended way to identify signals with low coverage is to use the annotation mechanism. The annotation mechanism is provided by the [verilator_coverage](https://github.com/verilator/verilator/blob/master/bin/verilator_coverage) tool and is capable of writing source files with annotations next to each coverage point. Coverage reports in the form of `.dat` files can be combined using the following command: ``` verilator_coverage coverage_test_*.dat --write combined.dat ``` In order to annotate the coverage results back to the source files, run the command: ``` verilator_coverage coverage_test.dat --annotate ``` ```{note} `annotate-all`, `annotate-min` and `annotate-points` can be used to modify the behavior of the `annotate` option. For more details, see [Verilator Argument Reference](https://verilator.org/guide/latest/exe_verilator_coverage.html) ``` The result of the command should be a copy of the source files used in the simulation, located in the output directory of choice. In the annotated source files, you will find that annotations are placed at the beginning of lines, e.g.: ``` 153724 input logic en; %000000 input logic scan_mode; ``` Interpretations of these results are placed inline: ``` 153724 input logic en; // there were 153724 coverage hits %000000 input logic scan_mode; // signal never toggled, so line starts with '%' ``` If a single line contains more than one signal definition (or a multi-bit signal), it may be useful to run with the `annotate-points` argument, so that the annotation resembles: ``` 153888 input logic SE, EN, CK, -000000 point: comment=SE +153888 point: comment=EN +2636790 point: comment=CK ``` In this mode, '+' and '-' are used to indicate whether a coverage point is above or below the threshold. To read more about coverage in Verilator, see: * [Coverage analysis](https://verilator.org/guide/latest/simulating.html#coverage-analysis) * [verilator_coverage executable documentation](https://verilator.org/guide/latest/exe_verilator_coverage.html) ================================================ FILE: docs/update_styles.sh ================================================ #!/bin/bash SELF_DIR="$(dirname $(readlink -f ${BASH_SOURCE[0]}))" check_args_count(){ # Check argument count function is meant to be used to check if # the number of received arguments is equal to the expected. # If they are unequal, the function returns with error # Args: # argc_got - Number of received arguments, e.g.: $# # argc_expected - Number of expected arguments, e.g.: 2 argc_got=$1 argc_expected=$2 if [ ${argc_got} -ne ${argc_expected} ]; then echo -e "${COLOR_WHITE}Expected ${argc_expected} arguments, but received ${argc_got} ${COLOR_RED}FAIL${COLOR_CLEAR}" echo -e "${COLOR_WHITE}Caller:${COLOR_CLEAR}" `caller` exit 1 fi } update_styles(){ # Update styles for Sphinx theme # Args: # BUILDDIR - path to where the webpage is made BUILD_DIR=$1 echo -e "${COLOR_WHITE}========== Update styles =========${COLOR_CLEAR}" echo -e "${COLOR_WHITE} BUILD_DIR = ${BUILD_DIR}${COLOR_CLEAR}" # Replace styles for sphinx build cp dashboard-styles/main.css ${BUILD_DIR}/html/_static/ # Add CHIPs logo cp dashboard-styles/assets/chips-alliance-logo-mono.svg ${BUILD_DIR}/html/_static/white.svg # Replace undesired CSS and progress bar sprites with desired style for LCOV reports copy_files(){ check_args_count $# 2 SOURCE=$1 SEARCH=$2 FILES=`find ${BUILD_DIR}/ -name ${SEARCH}` for FILE in ${FILES}; do echo "Copy ${SOURCE} to ${FILE}" cp $SOURCE $FILE done } CHIPS_GCOV_CSS=dashboard-styles/gcov.css AMBER=dashboard-styles/assets/amber.png RUBY=dashboard-styles/assets/ruby.png SNOW=dashboard-styles/assets/snow.png EMERALD=dashboard-styles/assets/emerald.png for ASSET in $CHIPS_GCOV_CSS $AMBER $RUBY $SNOW $EMERALD; do copy_files $ASSET $(basename "$ASSET") done echo -e "${COLOR_WHITE}Update styles ${COLOR_GREEN}SUCCEEDED${COLOR_CLEAR}" } check_args_count $# 1 update_styles "$@" ================================================ FILE: release-notes.md ================================================ # Release notes ## 2.0 * Extended the core with support for RISC-V User privilege level * Extended the core with support for PMP and ePMP functionalities * ICache memory is now exported from the main core and can be provided at SoC integration level * Many smaller changes and bugfixes * Extended the repository with an array of tests and CI covering various core configurations ## 1.4 * Upgraded bit-manipulation support for Zba, Zbb, Zbc, Zbe, Zbf, Zbp, Zbr, Zbs to `0.94` draft spec. * Zba, Zbb, Zbc and Zbs are enabled by default. Use `-set=bitmanip_zb*=1` to enable other sub-extensions. * Simulation performance improvement coding style changes in branch predictor and PIC * Several corner case and exotic bug fixes : * MPC run ack timing * Force halt mechanism and MPC * Store data collision with DCCM DMA error when address is 0x0 * RAW hazard on mtdata1 * Errors on DMA access could leak into Dbg abstract cmd ocurring at same time * Icache parity error and branch error collision leading to fwd progress issue * Fixed linter warning for async reset ## 1.3 * Multiple debug module compliance deviations and bugs reported by Codasip * Updates to debug module to level compliance to version 0.13.2 of debug spec * Trigger chaining compliance fixes * Power optimization improvements and clock gating improvements * Significantly lower power in sleep as well as normal operation. * Enhanced debug memory abstract command to access internal as well as external memories * Added bit-manipulation support for Zba, Zbb, Zbc, Zbe, Zbf, Zbp, Zbr, Zbs (Jan 29, 2020 Draft spec). * Zbs and Zbb are enabled by default. Use `-set=bitmanip_zb*=1` to enable other sub-extensions. * Enhancements and additional configurations options for a faster divider * JTAG bypass register intial state issue fixed * New branch predictor fully-associative option with 8,16,32 entries. * Corner case bugs fixes related to * Bus protocol corner cases (ahb) * Fetch bus error recording improved accuracy * Branch predictor pathological timing cases fixes * Fast interrupt with DCCM ECC errors priority bug * MPC & PMU protocol cleanup * Performance counter bug fixes (counting branch prediction events) * Triggers and ECC correctable error overflows bug fixes * Demo test-bench updates * Handling bigger test sizes using associative arrays in external memory slaves, * simplified test building process and CCM loading functions (only program.hex is generated, no data.hex) * Improved Makefile and example tests (see README) * Generating link.ld with veer.config ## 1.2 * Modified MSCAUSE encoding to be consistent with current internal specification * Added internal timers ## 1.1 * Several bug fixes in debug module * Added new `dbg_rst_l` input for system wide reset to debug module. If debug module operation during core reset is not needed, this can be connected to `rst_l`. * Trace port width adjusted * Demo testbench has a synthesizable bridge to allow accessing the ICCM with load/stores via the DMA port. (*This only works with the AXI4 build*) ## 1.0 Initial release ================================================ FILE: requirements.txt ================================================ # Build and Workflow Tools nox meson # Linters isort black flake8 # Documentation Sphinx>=8.0.2,<9 # Sphinx utilities https://github.com/antmicro/antmicro-sphinx-utils/archive/main.zip # Verification - Core # Note: Custom cocotb might be required for some flows # ./third_party/cocotb cocotb==1.8.0 cocotb-bus==0.2.1 cocotb-coverage==1.1.0 cocotb-test==0.2.4 pyuvm==2.9.1 # Verification - Testing & Reporting pytest==9.0.3 pytest-html==3.2.0 pytest-timeout==2.1.0 pytest-md==0.2.0 # Scientific/Math (used in some block tests) scipy==1.13.1 ================================================ FILE: testbench/ahb_lite_2to1_mux.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ------------------------------------------------------------- // AHB Lite 2:1 Mux // ------------------------------------------------------------- module ahb_lite_2to1_mux #( parameter AHB_LITE_ADDR_WIDTH = 32, parameter AHB_LITE_DATA_WIDTH = 32, parameter AHB_NO_OPT = 0 ) ( // --------------------------------------- // Global clock/reset // --------------------------------------- input logic hclk, input logic hreset_n, input logic force_bus_idle, // --------------------------------------- // From Initiator 0 // --------------------------------------- input logic hsel_i_0, input logic [AHB_LITE_ADDR_WIDTH-1:0] haddr_i_0, input logic [AHB_LITE_DATA_WIDTH-1:0] hwdata_i_0, input logic hwrite_i_0, input logic [1:0] htrans_i_0, input logic [2:0] hsize_i_0, input logic hready_i_0, output logic hresp_o_0, output logic hready_o_0, output logic [AHB_LITE_DATA_WIDTH-1:0] hrdata_o_0, // --------------------------------------- // From Initiator 1 // --------------------------------------- input logic hsel_i_1, input logic [AHB_LITE_ADDR_WIDTH-1:0] haddr_i_1, input logic [AHB_LITE_DATA_WIDTH-1:0] hwdata_i_1, input logic hwrite_i_1, input logic [1:0] htrans_i_1, input logic [2:0] hsize_i_1, input logic hready_i_1, output logic hresp_o_1, output logic hready_o_1, output logic [AHB_LITE_DATA_WIDTH-1:0] hrdata_o_1, // --------------------------------------- // To Responder Interface Port // --------------------------------------- input logic hresp_i, input logic [AHB_LITE_DATA_WIDTH-1:0] hrdata_i, input logic hreadyout_i, output logic [AHB_LITE_ADDR_WIDTH-1:0] haddr_o, output logic [AHB_LITE_DATA_WIDTH-1:0] hwdata_o, output logic hsel_o, output logic hwrite_o, output logic hready_o, output logic [1:0] htrans_o, output logic [2:0] hsize_o ); //This is a fixed priority 2:1 mux for AHB-Lite protocol //Initiator 0 always takes priority logic initiator0_address_ph, initiator1_address_ph; logic initiator0_data_ph_nq, initiator1_data_ph_nq; logic initiator0_data_ph, initiator1_data_ph; logic initiator0_pend_addr_ph_nq, initiator1_pend_addr_ph_nq; logic initiator0_pend_addr_ph, initiator1_pend_addr_ph; logic initiator0_gnt, initiator1_gnt; logic [AHB_LITE_ADDR_WIDTH-1:0] initiator0_pend_haddr, initiator1_pend_haddr; logic [AHB_LITE_ADDR_WIDTH-1:0] initiator0_haddr, initiator1_haddr; logic [1:0] initiator0_pend_htrans, initiator1_pend_htrans; logic [1:0] initiator0_htrans, initiator1_htrans; logic [2:0] initiator0_pend_hsize, initiator1_pend_hsize; logic [2:0] initiator0_hsize, initiator1_hsize; logic initiator0_pend_hwrite, initiator1_pend_hwrite; logic initiator0_hwrite, initiator1_hwrite; //Detect address phase always_comb initiator0_address_ph = hsel_i_0 & hready_i_0 & htrans_i_0 inside {2'b10, 2'b11} & ~force_bus_idle; always_comb initiator1_address_ph = hsel_i_1 & hready_i_1 & htrans_i_1 inside {2'b10, 2'b11} & ~force_bus_idle; always_ff @(posedge hclk or negedge hreset_n) begin if (~hreset_n) begin initiator0_pend_haddr <= '0; initiator1_pend_haddr <= '0; initiator0_pend_htrans <= '0; initiator1_pend_htrans <= '0; initiator0_pend_hsize <= '0; initiator1_pend_hsize <= '0; initiator0_pend_hwrite <= '0; initiator1_pend_hwrite <= '0; initiator0_pend_addr_ph_nq <= '0; initiator1_pend_addr_ph_nq <= '0; initiator0_data_ph_nq <= '0; initiator1_data_ph_nq <= '0; end else begin //Capture the address during the address phase for each initiator initiator0_pend_haddr <= initiator0_address_ph & ~initiator0_pend_addr_ph ? haddr_i_0 : initiator0_pend_haddr; initiator1_pend_haddr <= initiator1_address_ph & ~initiator1_pend_addr_ph ? haddr_i_1 : initiator1_pend_haddr; initiator0_pend_htrans <= initiator0_address_ph & ~initiator0_pend_addr_ph ? htrans_i_0 : initiator0_pend_htrans; initiator1_pend_htrans <= initiator1_address_ph & ~initiator1_pend_addr_ph ? htrans_i_1 : initiator1_pend_htrans; initiator0_pend_hsize <= initiator0_address_ph & ~initiator0_pend_addr_ph ? hsize_i_0 : initiator0_pend_hsize; initiator1_pend_hsize <= initiator1_address_ph & ~initiator1_pend_addr_ph ? hsize_i_1 : initiator1_pend_hsize; initiator0_pend_hwrite <= initiator0_address_ph & ~initiator0_pend_addr_ph ? hwrite_i_0 : initiator0_pend_hwrite; initiator1_pend_hwrite <= initiator1_address_ph & ~initiator1_pend_addr_ph ? hwrite_i_1 : initiator1_pend_hwrite; //Capture pending address phase when initiators collide initiator0_pend_addr_ph_nq <= (initiator0_address_ph | initiator0_pend_addr_ph) & ~(hreadyout_i & initiator0_gnt); initiator1_pend_addr_ph_nq <= (initiator1_address_ph | initiator1_pend_addr_ph) & ~(hreadyout_i & initiator1_gnt); //Transition to data phase when endpoint accepts address phase, hold when not ready initiator0_data_ph_nq <= (initiator0_gnt) | (initiator0_data_ph & ~hreadyout_i); initiator1_data_ph_nq <= (initiator1_gnt) | (initiator1_data_ph & ~hreadyout_i); end end always_comb initiator0_data_ph = initiator0_data_ph_nq & ~force_bus_idle; always_comb initiator1_data_ph = initiator1_data_ph_nq & ~force_bus_idle; always_comb initiator0_pend_addr_ph = initiator0_pend_addr_ph_nq & ~force_bus_idle; always_comb initiator1_pend_addr_ph = initiator1_pend_addr_ph_nq & ~force_bus_idle; always_comb initiator0_haddr = initiator0_pend_addr_ph ? initiator0_pend_haddr : haddr_i_0; always_comb initiator0_htrans = initiator0_pend_addr_ph ? initiator0_pend_htrans : htrans_i_0; always_comb initiator0_hsize = initiator0_pend_addr_ph ? initiator0_pend_hsize : hsize_i_0; always_comb initiator0_hwrite = initiator0_pend_addr_ph ? initiator0_pend_hwrite : hwrite_i_0; always_comb initiator1_haddr = initiator1_pend_addr_ph ? initiator1_pend_haddr : haddr_i_1; always_comb initiator1_htrans = initiator1_pend_addr_ph ? initiator1_pend_htrans : htrans_i_1; always_comb initiator1_hsize = initiator1_pend_addr_ph ? initiator1_pend_hsize : hsize_i_1; always_comb initiator1_hwrite = initiator1_pend_addr_ph ? initiator1_pend_hwrite : hwrite_i_1; //Select the appropriate initiator generate if (AHB_NO_OPT) begin //no optimization, data phase must complete before driving new address phase //Initiator 0 gets priority //Stall the grant only if initiator 1 is on its data phase always_comb initiator0_gnt = (initiator0_address_ph | initiator0_pend_addr_ph) & ~initiator1_data_ph; //Initiator 1 gets through only if initiator 0 address phase isn't getting gnt, or in data phase always_comb initiator1_gnt = (initiator1_address_ph | initiator1_pend_addr_ph) & ~initiator0_data_ph & ~initiator0_gnt; end else begin //optimized to allow addr phase to overlap data phase, assumes no stalls //Initiator 0 gets priority //Stall the grant if initiator 1 is processing a data phase and address phase b2b always_comb initiator0_gnt = (initiator0_address_ph | initiator0_pend_addr_ph); //Initiator 1 gets through only if initiator 0 isn't getting granted always_comb initiator1_gnt = (initiator1_address_ph | initiator1_pend_addr_ph) & ~initiator0_gnt; end endgenerate //Mux the appropriate initiator and send out //Keep driving initiator 1 controls on data phase if init0 isn't getting a grant in that cycle always_comb haddr_o = initiator1_gnt | (initiator1_data_ph & ~initiator0_gnt) ? initiator1_haddr : initiator0_haddr; always_comb htrans_o = initiator1_gnt | (initiator1_data_ph & ~initiator0_gnt) ? initiator1_htrans : initiator0_htrans; always_comb hsize_o = initiator1_gnt | (initiator1_data_ph & ~initiator0_gnt) ? initiator1_hsize : initiator0_hsize; always_comb hwrite_o = initiator1_gnt | (initiator1_data_ph & ~initiator0_gnt) ? initiator1_hwrite : initiator0_hwrite; always_comb hsel_o = initiator1_gnt | (initiator1_data_ph & ~initiator0_gnt) ? hsel_i_1 : hsel_i_0; always_comb hwdata_o = initiator1_gnt | (initiator1_data_ph & ~initiator0_gnt) ? hwdata_i_1 : hwdata_i_0; always_comb hready_o = initiator1_gnt | (initiator1_data_ph & ~initiator0_gnt) ? (hready_i_1 | initiator1_pend_addr_ph) : (hready_i_0 | initiator0_pend_addr_ph); //Send response to the initiator //Mask the ready when it's a pending address phase //Send the data coming from responder when selected always_comb hresp_o_0 = initiator0_data_ph ? hresp_i : '0; always_comb hrdata_o_0 = initiator0_data_ph ? hrdata_i : '0; always_comb hready_o_0 = initiator0_data_ph ? hreadyout_i : initiator0_pend_addr_ph ? '0 : '1; always_comb hresp_o_1 = initiator1_data_ph? hresp_i: '0; always_comb hrdata_o_1 = initiator1_data_ph ? hrdata_i: '0; always_comb hready_o_1 = initiator1_data_ph ? hreadyout_i : initiator1_pend_addr_ph ? '0 : '1; //Coverage `ifndef VERILATOR `ifdef FCOV covergroup ahb_lite_2to1_mux_cov_grp @(posedge hclk iff hreset_n); option.per_instance = 1; init0_addr_cp: coverpoint initiator0_address_ph; init0_pend_addr_cp: coverpoint initiator0_pend_addr_ph; init0_data_cp: coverpoint initiator0_data_ph; init0_gnt_cp : coverpoint initiator0_gnt; init1_addr_cp: coverpoint initiator1_address_ph; init1_pend_addr_cp: coverpoint initiator1_pend_addr_ph; init1_data_cp: coverpoint initiator1_data_ph; init1_gnt_cp : coverpoint initiator1_gnt; init0_pend_addr_not_ready: coverpoint initiator0_pend_addr_ph & ~hreadyout_i; init1_pend_addr_not_ready: coverpoint initiator1_pend_addr_ph & ~hreadyout_i; init0_data_not_ready: coverpoint initiator0_data_ph & ~hreadyout_i; init1_data_not_ready: coverpoint initiator1_data_ph & ~hreadyout_i; init0_dataXinit1_gnt: cross init0_data_cp, init1_gnt_cp; init1_dataXinit0_gnt: cross init1_data_cp, init0_gnt_cp; init0_addrXpend: cross init0_addr_cp, init0_pend_addr_cp; init1_addrXpend: cross init1_addr_cp, init1_pend_addr_cp; init0Xinit1_addr: cross init0_addr_cp, init1_addr_cp; init0Xinit1_pend_addr: cross init0_pend_addr_cp, init1_pend_addr_cp; endgroup ahb_lite_2to1_mux_cov_grp ahb_lite_2to1_mux_cov_grp1 = new(); `endif `endif endmodule ================================================ FILE: testbench/ahb_lsu_dma_bridge.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // connects LSU master (AHB) to external AXI slave and DMA slave (AHB) module ahb_lsu_dma_bridge #( TAG = 1, `include "el2_param.vh" ) ( input clk, input reset_l, // AHB master interface (LSU) input logic [31:0] m_ahb_haddr, // ahb bus address input logic [2:0] m_ahb_hburst, // tied to 0 input logic m_ahb_hmastlock, // tied to 0 input logic [3:0] m_ahb_hprot, // tied to 4'b0011 input logic [2:0] m_ahb_hsize, // size of bus transaction (possible values 0,1,2,3) input logic [1:0] m_ahb_htrans, // Transaction type (possible values 0,2 only right now) input logic m_ahb_hwrite, // ahb bus write input logic [63:0] m_ahb_hwdata, // ahb bus write data input logic m_ahb_hsel, // this slave was selected input logic m_ahb_hreadyin, // previous hready was accepted or not output logic [63:0] m_ahb_hrdata, // ahb bus read data output logic m_ahb_hreadyout, // slave ready to accept transaction output logic m_ahb_hresp, // slave response (high indicates erro) // AHB slave interface (lmem) output logic s0_ahb_hsel, // ahb bus slave select output logic [31:0] s0_ahb_haddr, // ahb bus address output logic [2:0] s0_ahb_hburst, // tied to 0 output logic s0_ahb_hmastlock, // tied to 0 output logic [3:0] s0_ahb_hprot, // [3:1] are tied to 3'b001 output logic [2:0] s0_ahb_hsize, // size of bus transaction (possible values 0,1,2,3) output logic [1:0] s0_ahb_htrans, // Transaction type (possible values 0,2 only right now) output logic s0_ahb_hwrite, // ahb bus write output logic [63:0] s0_ahb_hwdata, // ahb bus write data input logic [63:0] s0_ahb_hrdata, // ahb bus read data input logic s0_ahb_hready, // connect to veer's dma_hreadyout input logic s0_ahb_hresp, // slave response (high indicates erro) // AHB slave interface (dma) output logic s1_ahb_hsel, // ahb bus slave select output logic [31:0] s1_ahb_haddr, // ahb bus address output logic [2:0] s1_ahb_hburst, // tied to 0 output logic s1_ahb_hmastlock, // tied to 0 output logic [3:0] s1_ahb_hprot, // [3:1] are tied to 3'b001 output logic [2:0] s1_ahb_hsize, // size of bus transaction (possible values 0,1,2,3) output logic [1:0] s1_ahb_htrans, // Transaction type (possible values 0,2 only right now) output logic s1_ahb_hwrite, // ahb bus write output logic [63:0] s1_ahb_hwdata, // ahb bus write data input logic [63:0] s1_ahb_hrdata, // ahb bus read data input logic s1_ahb_hready, // connect to veer's dma_hreadyout input logic s1_ahb_hresp // slave response (high indicates erro) ); parameter ICCM_BASE = `RV_ICCM_BITS; // in LSBs bit[31:0] iccm_real_base_addr = `RV_ICCM_SADR ; wire bus_active; wire slave_select; reg slave_select_dly; assign bus_active = m_ahb_htrans inside {2'b10, 2'b11}; assign slave_select = m_ahb_haddr[31:ICCM_BASE] == iccm_real_base_addr[31:ICCM_BASE]; assign s0_ahb_hsel = bus_active & ~slave_select; assign s0_ahb_haddr = m_ahb_haddr; assign s0_ahb_hburst = m_ahb_hburst; assign s0_ahb_hmastlock = m_ahb_hmastlock; assign s0_ahb_hprot = m_ahb_hprot; assign s0_ahb_hsize = m_ahb_hsize; assign s0_ahb_htrans = m_ahb_htrans; assign s0_ahb_hwrite = m_ahb_hwrite; assign s0_ahb_hwdata = m_ahb_hwdata; assign s1_ahb_hsel = bus_active & slave_select; assign s1_ahb_haddr = m_ahb_haddr; assign s1_ahb_hburst = m_ahb_hburst; assign s1_ahb_hmastlock = m_ahb_hmastlock; assign s1_ahb_hprot = m_ahb_hprot; assign s1_ahb_hsize = m_ahb_hsize; assign s1_ahb_htrans = m_ahb_htrans; assign s1_ahb_hwrite = m_ahb_hwrite; assign s1_ahb_hwdata = m_ahb_hwdata; assign m_ahb_hreadyout = &{s0_ahb_hready, s1_ahb_hready}; assign m_ahb_hrdata = slave_select_dly ? s1_ahb_hrdata : s0_ahb_hrdata; assign m_ahb_hresp = slave_select_dly ? s1_ahb_hresp : s0_ahb_hresp; always_ff @(posedge clk or negedge reset_l) begin if(~reset_l) slave_select_dly <= 1'b0; else slave_select_dly <= slave_select; end endmodule ================================================ FILE: testbench/ahb_sif.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2019 Western Digital Corporation or its affiliates. // Copyright 2024 Antmicro // // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // `ifdef RV_BUILD_AHB_LITE module ahb_sif #( parameter int MAX_DELAY = -1, parameter int MIN_DELAY = 0 ) ( input logic [63:0] HWDATA, input logic HCLK, input logic HSEL, input logic [3:0] HPROT, input logic HWRITE, input logic [1:0] HTRANS, input logic [2:0] HSIZE, input logic HREADY, input logic HRESETn, input logic [31:0] HADDR, input logic [2:0] HBURST, output logic HREADYOUT, output logic HRESP, output logic [63:0] HRDATA ); logic write; logic [31:0] laddr, addr; logic [7:0] strb_lat; logic [63:0] rdata; bit [7:0] mem[bit [31:0]]; bit [7:0] wscnt; int dws = 0; int iws = 0; bit dws_rand; bit iws_rand; bit ok; // Wires wire [7:0] strb = HSIZE == 3'b000 ? 8'h1 << HADDR[2:0] : HSIZE == 3'b001 ? 8'h3 << {HADDR[2:1],1'b0} : HSIZE == 3'b010 ? 8'hf << {HADDR[2],2'b0} : 8'hff; initial begin if ($value$plusargs("iws=%d", iws)); if ($value$plusargs("dws=%d", dws)); dws_rand = dws < 0; iws_rand = iws < 0; end always @(negedge HCLK) begin if (HREADY) addr = HADDR; if (write & HREADY) begin if (strb_lat[7]) mem[{laddr[31:3], 3'd7}] = HWDATA[63:56]; if (strb_lat[6]) mem[{laddr[31:3], 3'd6}] = HWDATA[55:48]; if (strb_lat[5]) mem[{laddr[31:3], 3'd5}] = HWDATA[47:40]; if (strb_lat[4]) mem[{laddr[31:3], 3'd4}] = HWDATA[39:32]; if (strb_lat[3]) mem[{laddr[31:3], 3'd3}] = HWDATA[31:24]; if (strb_lat[2]) mem[{laddr[31:3], 3'd2}] = HWDATA[23:16]; if (strb_lat[1]) mem[{laddr[31:3], 3'd1}] = HWDATA[15:08]; if (strb_lat[0]) mem[{laddr[31:3], 3'd0}] = HWDATA[07:00]; end if (HREADY & HSEL & |HTRANS) begin if (MAX_DELAY < 0) begin `ifdef VERILATOR if (iws_rand & ~HPROT[0]) iws = $random & 15; if (dws_rand & HPROT[0]) dws = $random & 15; `else if (iws_rand & ~HPROT[0]) ok = std::randomize( iws ) with { iws dist { 0 := 10, [1 : 3] :/ 2, [4 : 15] :/ 1 }; }; if (dws_rand & HPROT[0]) ok = std::randomize( dws ) with { dws dist { 0 := 10, [1 : 3] :/ 2, [4 : 15] :/ 1 }; }; `endif end else begin if (~HPROT[0]) iws = MIN_DELAY + $random % (MAX_DELAY-MIN_DELAY+1); if (HPROT[0]) dws = MIN_DELAY + $random % (MAX_DELAY-MIN_DELAY+1); end end end assign HRDATA = HREADY ? rdata : ~rdata; assign HREADYOUT = wscnt == 0; assign HRESP = 0; always @(posedge HCLK or negedge HRESETn) begin if (~HRESETn) begin laddr <= 32'b0; write <= 1'b0; rdata <= '0; wscnt <= 0; end else begin if (HREADY & HSEL) begin laddr <= HADDR; write <= HWRITE & |HTRANS; if (|HTRANS & ~HWRITE) rdata <= { mem[{addr[31:3], 3'd7}] & {8{strb[7]}}, mem[{addr[31:3], 3'd6}] & {8{strb[6]}}, mem[{addr[31:3], 3'd5}] & {8{strb[5]}}, mem[{addr[31:3], 3'd4}] & {8{strb[4]}}, mem[{addr[31:3], 3'd3}] & {8{strb[3]}}, mem[{addr[31:3], 3'd2}] & {8{strb[2]}}, mem[{addr[31:3], 3'd1}] & {8{strb[1]}}, mem[{addr[31:3], 3'd0}] & {8{strb[0]}} }; strb_lat <= strb; end end if (HREADY & HSEL & |HTRANS) wscnt <= HPROT[0] ? dws[7:0] : iws[7:0]; else if (wscnt != 0) wscnt <= wscnt - 1; end endmodule `endif module axi_slv #( TAGW = 1 ) ( input aclk, input rst_l, input arvalid, output reg arready, input [ 31:0] araddr, input [TAGW-1:0] arid, input [ 7:0] arlen, input [ 1:0] arburst, input [ 2:0] arsize, output reg rvalid, input rready, output reg [ 63:0] rdata, output reg [ 1:0] rresp, output reg [TAGW-1:0] rid, output reg rlast, input awvalid, output reg awready, input [ 31:0] awaddr, input [TAGW-1:0] awid, input [ 7:0] awlen, input [ 1:0] awburst, input [ 2:0] awsize, input [63:0] wdata, input [ 7:0] wstrb, input wvalid, output reg wready, output reg bvalid, input bready, output reg [ 1:0] bresp, output reg [TAGW-1:0] bid ); bit [7:0] mem[bit [31:0]]; bit [31:0] write_address; bit [31:0] read_address; initial begin wready = 1; awready = 1; arready = 1'b1; rlast = 1'b0; rvalid = 0; bvalid = 0; end always @(posedge aclk) begin if (arvalid && arready) begin read_address = {araddr[31:3], 3'b000}; rdata <= { mem[read_address+7], mem[read_address+6], mem[read_address+5], mem[read_address+4], mem[read_address+3], mem[read_address+2], mem[read_address+1], mem[read_address] }; arready <= 0; rvalid <= 1; rid <= arid; rlast <= 1; rresp <= 0; end else if (rready) begin rvalid <= 0; arready <= 1; rlast <= 0; end if (awvalid) begin write_address = {awaddr[31:3], 3'b000}; awready <= 0; end if (wvalid) begin bid <= awid; bvalid <= 1; wready <= 0; bresp <= 0; if (wstrb[7]) mem[write_address+7] = wdata[63:56]; if (wstrb[6]) mem[write_address+6] = wdata[55:48]; if (wstrb[5]) mem[write_address+5] = wdata[47:40]; if (wstrb[4]) mem[write_address+4] = wdata[39:32]; if (wstrb[3]) mem[write_address+3] = wdata[31:24]; if (wstrb[2]) mem[write_address+2] = wdata[23:16]; if (wstrb[1]) mem[write_address+1] = wdata[15:08]; if (wstrb[0]) mem[write_address+0] = wdata[07:00]; end if (bready && bvalid) begin bvalid <= 0; awready <= 1; wready <= 1; end end endmodule ================================================ FILE: testbench/asm/bitmanip.s ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #define STDOUT 0xd0580000 #define RESULT_SUCCESS 0xff #define RESULT_FAILURE 0x1 // 5-bit encodings of registers #define reg_map(x) reg_map__##x #define reg_map__t0 5 #define reg_map__t1 6 #define reg_map__t2 7 #define INSTR_TWO_ARG(rd, rs1, rs2) (reg_map(rd) << 7 | reg_map(rs1) << 15 | reg_map(rs2) << 20) #define INSTR_ONE_ARG(rd, rs1) (reg_map(rd) << 7 | reg_map(rs1) << 15) // Implement instructions not implemented in the toolchain (Bitmanip Extenstion 0.94-draft, Jan 20, 2021) #define crc32_b(rd, rs1) .word (0b0110000 << 25 | (0b10000) << 20 | INSTR_ONE_ARG(rd, rs1) | 0b001 << 12 | 0b0010011) #define crc32_h(rd, rs1) .word (0b0110000 << 25 | (0b10001) << 20 | INSTR_ONE_ARG(rd, rs1) | 0b001 << 12 | 0b0010011) #define crc32_w(rd, rs1) .word (0b0110000 << 25 | (0b10010) << 20 | INSTR_ONE_ARG(rd, rs1) | 0b001 << 12 | 0b0010011) #define crc32_d(rd, rs1) .word (0b0110000 << 25 | (0b10011) << 20 | INSTR_ONE_ARG(rd, rs1) | 0b001 << 12 | 0b0010011) #define crc32c_b(rd, rs1) .word (0b0110000 << 25 | (0b11000) << 20 | INSTR_ONE_ARG(rd, rs1) | 0b001 << 12 | 0b0010011) #define crc32c_h(rd, rs1) .word (0b0110000 << 25 | (0b11001) << 20 | INSTR_ONE_ARG(rd, rs1) | 0b001 << 12 | 0b0010011) #define crc32c_w(rd, rs1) .word (0b0110000 << 25 | (0b11010) << 20 | INSTR_ONE_ARG(rd, rs1) | 0b001 << 12 | 0b0010011) #define crc32c_d(rd, rs1) .word (0b0110000 << 25 | (0b11011) << 20 | INSTR_ONE_ARG(rd, rs1) | 0b001 << 12 | 0b0010011) #define shfl(rd, rs1, rs2) .word (0b0000100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b001 << 12 | 0b0110011) #define unshfl(rd, rs1, rs2) .word (0b0000100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b101 << 12 | 0b0110011) #define bdecompress(rd, rs1, rs2) .word (0b0100100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b110 << 12 | 0b0110011) #define bcompress(rd, rs1, rs2) .word (0b0000100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b110 << 12 | 0b0110011) #define bfp(rd, rs1, rs2) .word (0b0100100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b111 << 12 | 0b0110011) #define grev(rd, rs1, rs2) .word (0b0110100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b101 << 12 | 0b0110011) #define gorc(rd, rs1, rs2) .word (0b0010100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b101 << 12 | 0b0110011) #define xperm_n(rd, rs1, rs2) .word (0b0010100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b010 << 12 | 0b0110011) #define xperm_b(rd, rs1, rs2) .word (0b0010100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b100 << 12 | 0b0110011) #define xperm_h(rd, rs1, rs2) .word (0b0010100 << 25 | INSTR_TWO_ARG(rd, rs1, rs2) | 0b110 << 12 | 0b0110011) #define EQUAL_OR_FAIL(reg, value) \ li t3, value; \ bne reg, t3, test_failed .global _start _start: li t0, 0xc0de // arg1 li t1, 0xdec0de // arg2 li t2, 0 // result test_bcompress: bcompress(t2, t0, t1) EQUAL_OR_FAIL(t2, 0xff) test_bdcompress: bdecompress(t2, t0, t1) EQUAL_OR_FAIL(t2, 0xc05c) test_grev: grev(t2, t0, t1) EQUAL_OR_FAIL(t2, 0xb7030000) test_gorc: gorc(t2, t0, t1) EQUAL_OR_FAIL(t2, 0xffffffff) test_shfl: shfl(t2, t0, t1) EQUAL_OR_FAIL(t2, 0x30003132) test_unshfl: unshfl(t2, t0, t1) EQUAL_OR_FAIL(t2, 0xcf0006) test_crc32_b: crc32_b(t2, t1) EQUAL_OR_FAIL(t2, 0x616b2113) test_crc32_h: crc32_h(t2, t1) EQUAL_OR_FAIL(t2, 0x84df2aff) test_crc32_w: crc32_w(t2, t1) EQUAL_OR_FAIL(t2, 0x489fb07b) test_crc32c_b: crc32c_b(t2, t1) EQUAL_OR_FAIL(t2, 0x7fab804c) test_crc32c_h: crc32c_h(t2, t1) EQUAL_OR_FAIL(t2, 0xc4779ec) test_crc32c_w: crc32c_w(t2, t1) EQUAL_OR_FAIL(t2, 0xa1ebfe1d) test_xperm_n: xperm_n(t2, t0, t1) EQUAL_OR_FAIL(t2, 0xee000e00) test_xperm_b: xperm_b(t2, t0, t1) EQUAL_OR_FAIL(t2, 0xde000000) test_xperm_h: xperm_h(t2, t0, t1) EQUAL_OR_FAIL(t2, 0x0) test_bfp: bfp(t2, t0, t1) EQUAL_OR_FAIL(t2, 0x8000c0de) success: li a0, STDOUT li a1, RESULT_SUCCESS sw a1, 0(a0) do_nothing: nop j do_nothing test_failed: li a0, STDOUT li a1, RESULT_FAILURE sw a1, 0(a0) .long 0 ================================================ FILE: testbench/asm/cmark.c ================================================ #include "defines.h" #define ITERATIONS 1 /* Author : Shay Gal-On, EEMBC This file is part of EEMBC(R) and CoreMark(TM), which are Copyright (C) 2009 All rights reserved. EEMBC CoreMark Software is a product of EEMBC and is provided under the terms of the CoreMark License that is distributed with the official EEMBC COREMARK Software release. If you received this EEMBC CoreMark Software without the accompanying CoreMark License, you must discontinue use and download the official release from www.coremark.org. Also, if you are publicly displaying scores generated from the EEMBC CoreMark software, make sure that you are in compliance with Run and Reporting rules specified in the accompanying readme.txt file. EEMBC 4354 Town Center Blvd. Suite 114-200 El Dorado Hills, CA, 95762 */ //#include "/wd/users/jrahmeh/coremark_v1.0/riscv/coremark.h" /* Author : Shay Gal-On, EEMBC This file is part of EEMBC(R) and CoreMark(TM), which are Copyright (C) 2009 All rights reserved. EEMBC CoreMark Software is a product of EEMBC and is provided under the terms of the CoreMark License that is distributed with the official EEMBC COREMARK Software release. If you received this EEMBC CoreMark Software without the accompanying CoreMark License, you must discontinue use and download the official release from www.coremark.org. Also, if you are publicly displaying scores generated from the EEMBC CoreMark software, make sure that you are in compliance with Run and Reporting rules specified in the accompanying readme.txt file. EEMBC 4354 Town Center Blvd. Suite 114-200 El Dorado Hills, CA, 95762 */ /* Topic: Description This file contains declarations of the various benchmark functions. */ /* Configuration: TOTAL_DATA_SIZE Define total size for data algorithms will operate on */ #ifndef TOTAL_DATA_SIZE #define TOTAL_DATA_SIZE 2*1000 #endif #define SEED_ARG 0 #define SEED_FUNC 1 #define SEED_VOLATILE 2 #define MEM_STATIC 0 #define MEM_MALLOC 1 #define MEM_STACK 2 /* File : core_portme.h */ /* Author : Shay Gal-On, EEMBC Legal : TODO! */ /* Topic : Description This file contains configuration constants required to execute on different platforms */ #ifndef CORE_PORTME_H #define CORE_PORTME_H /************************/ /* Data types and settings */ /************************/ /* Configuration : HAS_FLOAT Define to 1 if the platform supports floating point. */ #ifndef HAS_FLOAT #define HAS_FLOAT 0 #endif /* Configuration : HAS_TIME_H Define to 1 if platform has the time.h header file, and implementation of functions thereof. */ #ifndef HAS_TIME_H #define HAS_TIME_H 0 #endif /* Configuration : USE_CLOCK Define to 1 if platform has the time.h header file, and implementation of functions thereof. */ #ifndef USE_CLOCK #define USE_CLOCK 0 #endif /* Configuration : HAS_STDIO Define to 1 if the platform has stdio.h. */ #ifndef HAS_STDIO #define HAS_STDIO 0 #endif /* Configuration : HAS_PRINTF Define to 1 if the platform has stdio.h and implements the printf function. */ #ifndef HAS_PRINTF #define HAS_PRINTF 1 int whisperPrintf(const char* format, ...); #define ee_printf whisperPrintf #endif /* Configuration : CORE_TICKS Define type of return from the timing functions. */ #include typedef clock_t CORE_TICKS; /* Definitions : COMPILER_VERSION, COMPILER_FLAGS, MEM_LOCATION Initialize these strings per platform */ #ifndef COMPILER_VERSION #ifdef __GNUC__ #define COMPILER_VERSION "GCC"__VERSION__ #else #define COMPILER_VERSION "Please put compiler version here (e.g. gcc 4.1)" #endif #endif #ifndef COMPILER_FLAGS #define COMPILER_FLAGS "-O2" #endif #ifndef MEM_LOCATION // #define MEM_LOCATION "STACK" #define MEM_LOCATION "STATIC" #endif /* Data Types : To avoid compiler issues, define the data types that need ot be used for 8b, 16b and 32b in . *Imprtant* : ee_ptr_int needs to be the data type used to hold pointers, otherwise coremark may fail!!! */ typedef signed short ee_s16; typedef unsigned short ee_u16; typedef signed int ee_s32; typedef double ee_f32; typedef unsigned char ee_u8; typedef unsigned int ee_u32; typedef ee_u32 ee_ptr_int; typedef size_t ee_size_t; /* align_mem : This macro is used to align an offset to point to a 32b value. It is used in the Matrix algorithm to initialize the input memory blocks. */ #define align_mem(x) (void *)(4 + (((ee_ptr_int)(x) - 1) & ~3)) /* Configuration : SEED_METHOD Defines method to get seed values that cannot be computed at compile time. Valid values : SEED_ARG - from command line. SEED_FUNC - from a system function. SEED_VOLATILE - from volatile variables. */ #ifndef SEED_METHOD #define SEED_METHOD SEED_VOLATILE #endif /* Configuration : MEM_METHOD Defines method to get a block of memry. Valid values : MEM_MALLOC - for platforms that implement malloc and have malloc.h. MEM_STATIC - to use a static memory array. MEM_STACK - to allocate the data block on the stack (NYI). */ #ifndef MEM_METHOD //#define MEM_METHOD MEM_STACK #define MEM_METHOD MEM_STATIC #endif /* Configuration : MULTITHREAD Define for parallel execution Valid values : 1 - only one context (default). N>1 - will execute N copies in parallel. Note : If this flag is defined to more then 1, an implementation for launching parallel contexts must be defined. Two sample implementations are provided. Use or to enable them. It is valid to have a different implementation of and in , to fit a particular architecture. */ #ifndef MULTITHREAD #define MULTITHREAD 1 #define USE_PTHREAD 0 #define USE_FORK 0 #define USE_SOCKET 0 #endif /* Configuration : MAIN_HAS_NOARGC Needed if platform does not support getting arguments to main. Valid values : 0 - argc/argv to main is supported 1 - argc/argv to main is not supported Note : This flag only matters if MULTITHREAD has been defined to a value greater then 1. */ #ifndef MAIN_HAS_NOARGC #define MAIN_HAS_NOARGC 1 #endif /* Configuration : MAIN_HAS_NORETURN Needed if platform does not support returning a value from main. Valid values : 0 - main returns an int, and return value will be 0. 1 - platform does not support returning a value from main */ #ifndef MAIN_HAS_NORETURN #define MAIN_HAS_NORETURN 0 #endif /* Variable : default_num_contexts Not used for this simple port, must cintain the value 1. */ extern ee_u32 default_num_contexts; typedef struct CORE_PORTABLE_S { ee_u8 portable_id; } core_portable; /* target specific init/fini */ void portable_init(core_portable *p, int *argc, char *argv[]); void portable_fini(core_portable *p); #if !defined(PROFILE_RUN) && !defined(PERFORMANCE_RUN) && !defined(VALIDATION_RUN) #if (TOTAL_DATA_SIZE==1200) #define PROFILE_RUN 1 #elif (TOTAL_DATA_SIZE==2000) #define PERFORMANCE_RUN 1 #else #define VALIDATION_RUN 1 #endif #endif #endif /* CORE_PORTME_H */ #if HAS_STDIO #include #endif #if HAS_PRINTF #ifndef ee_printf #define ee_printf printf #endif #endif /* Actual benchmark execution in iterate */ void *iterate(void *pres); /* Typedef: secs_ret For machines that have floating point support, get number of seconds as a double. Otherwise an unsigned int. */ #if HAS_FLOAT typedef double secs_ret; #else typedef ee_u32 secs_ret; #endif #if MAIN_HAS_NORETURN #define MAIN_RETURN_VAL #define MAIN_RETURN_TYPE void #else #define MAIN_RETURN_VAL 0 #define MAIN_RETURN_TYPE int #endif void start_time(void); void stop_time(void); CORE_TICKS get_time(void); secs_ret time_in_secs(CORE_TICKS ticks); /* Misc useful functions */ ee_u16 crcu8(ee_u8 data, ee_u16 crc); ee_u16 crc16(ee_s16 newval, ee_u16 crc); ee_u16 crcu16(ee_u16 newval, ee_u16 crc); ee_u16 crcu32(ee_u32 newval, ee_u16 crc); ee_u8 check_data_types(); void *portable_malloc(ee_size_t size); void portable_free(void *p); ee_s32 parseval(char *valstring); /* Algorithm IDS */ #define ID_LIST (1<<0) #define ID_MATRIX (1<<1) #define ID_STATE (1<<2) #define ALL_ALGORITHMS_MASK (ID_LIST|ID_MATRIX|ID_STATE) #define NUM_ALGORITHMS 3 /* list data structures */ typedef struct list_data_s { ee_s16 data16; ee_s16 idx; } list_data; typedef struct list_head_s { struct list_head_s *next; struct list_data_s *info; } list_head; /*matrix benchmark related stuff */ #define MATDAT_INT 1 #if MATDAT_INT typedef ee_s16 MATDAT; typedef ee_s32 MATRES; #else typedef ee_f16 MATDAT; typedef ee_f32 MATRES; #endif typedef struct MAT_PARAMS_S { int N; MATDAT *A; MATDAT *B; MATRES *C; } mat_params; /* state machine related stuff */ /* List of all the possible states for the FSM */ typedef enum CORE_STATE { CORE_START=0, CORE_INVALID, CORE_S1, CORE_S2, CORE_INT, CORE_FLOAT, CORE_EXPONENT, CORE_SCIENTIFIC, NUM_CORE_STATES } core_state_e ; /* Helper structure to hold results */ typedef struct RESULTS_S { /* inputs */ ee_s16 seed1; /* Initializing seed */ ee_s16 seed2; /* Initializing seed */ ee_s16 seed3; /* Initializing seed */ void *memblock[4]; /* Pointer to safe memory location */ ee_u32 size; /* Size of the data */ ee_u32 iterations; /* Number of iterations to execute */ ee_u32 execs; /* Bitmask of operations to execute */ struct list_head_s *list; mat_params mat; /* outputs */ ee_u16 crc; ee_u16 crclist; ee_u16 crcmatrix; ee_u16 crcstate; ee_s16 err; /* ultithread specific */ core_portable port; } core_results; /* Multicore execution handling */ #if (MULTITHREAD>1) ee_u8 core_start_parallel(core_results *res); ee_u8 core_stop_parallel(core_results *res); #endif /* list benchmark functions */ list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed); ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx); /* state benchmark functions */ void core_init_state(ee_u32 size, ee_s16 seed, ee_u8 *p); ee_u16 core_bench_state(ee_u32 blksize, ee_u8 *memblock, ee_s16 seed1, ee_s16 seed2, ee_s16 step, ee_u16 crc); /* matrix benchmark functions */ ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p); ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc); /* Topic: Description Benchmark using a linked list. Linked list is a common data structure used in many applications. For our purposes, this will excercise the memory units of the processor. In particular, usage of the list pointers to find and alter data. We are not using Malloc since some platforms do not support this library. Instead, the memory block being passed in is used to create a list, and the benchmark takes care not to add more items then can be accomodated by the memory block. The porting layer will make sure that we have a valid memory block. All operations are done in place, without using any extra memory. The list itself contains list pointers and pointers to data items. Data items contain the following: idx - An index that captures the initial order of the list. data - Variable data initialized based on the input parameters. The 16b are divided as follows: o Upper 8b are backup of original data. o Bit 7 indicates if the lower 7 bits are to be used as is or calculated. o Bits 0-2 indicate type of operation to perform to get a 7b value. o Bits 3-6 provide input for the operation. */ /* local functions */ list_head *core_list_find(list_head *list,list_data *info); list_head *core_list_reverse(list_head *list); list_head *core_list_remove(list_head *item); list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified); list_head *core_list_insert_new(list_head *insert_point , list_data *info, list_head **memblock, list_data **datablock , list_head *memblock_end, list_data *datablock_end); typedef ee_s32(*list_cmp)(list_data *a, list_data *b, core_results *res); list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res); ee_s16 calc_func(ee_s16 *pdata, core_results *res) { ee_s16 data=*pdata; ee_s16 retval; ee_u8 optype=(data>>7) & 1; /* bit 7 indicates if the function result has been cached */ if (optype) /* if cached, use cache */ return (data & 0x007f); else { /* otherwise calculate and cache the result */ ee_s16 flag=data & 0x7; /* bits 0-2 is type of function to perform */ ee_s16 dtype=((data>>3) & 0xf); /* bits 3-6 is specific data for the operation */ dtype |= dtype << 4; /* replicate the lower 4 bits to get an 8b value */ switch (flag) { case 0: if (dtype<0x22) /* set min period for bit corruption */ dtype=0x22; retval=core_bench_state(res->size,res->memblock[3],res->seed1,res->seed2,dtype,res->crc); if (res->crcstate==0) res->crcstate=retval; break; case 1: retval=core_bench_matrix(&(res->mat),dtype,res->crc); if (res->crcmatrix==0) res->crcmatrix=retval; break; default: retval=data; break; } res->crc=crcu16(retval,res->crc); retval &= 0x007f; *pdata = (data & 0xff00) | 0x0080 | retval; /* cache the result */ return retval; } } /* Function: cmp_complex Compare the data item in a list cell. Can be used by mergesort. */ ee_s32 cmp_complex(list_data *a, list_data *b, core_results *res) { ee_s16 val1=calc_func(&(a->data16),res); ee_s16 val2=calc_func(&(b->data16),res); return val1 - val2; } /* Function: cmp_idx Compare the idx item in a list cell, and regen the data. Can be used by mergesort. */ ee_s32 cmp_idx(list_data *a, list_data *b, core_results *res) { if (res==NULL) { a->data16 = (a->data16 & 0xff00) | (0x00ff & (a->data16>>8)); b->data16 = (b->data16 & 0xff00) | (0x00ff & (b->data16>>8)); } return a->idx - b->idx; } void copy_info(list_data *to,list_data *from) { to->data16=from->data16; to->idx=from->idx; } /* Benchmark for linked list: - Try to find multiple data items. - List sort - Operate on data from list (crc) - Single remove/reinsert * At the end of this function, the list is back to original state */ ee_u16 core_bench_list(core_results *res, ee_s16 finder_idx) { ee_u16 retval=0; ee_u16 found=0,missed=0; list_head *list=res->list; ee_s16 find_num=res->seed3; list_head *this_find; list_head *finder, *remover; list_data info; ee_s16 i; info.idx=finder_idx; /* find values in the list, and change the list each time (reverse and cache if value found) */ for (i=0; inext->info->data16 >> 8) & 1; } else { found++; if (this_find->info->data16 & 0x1) /* use found value */ retval+=(this_find->info->data16 >> 9) & 1; /* and cache next item at the head of the list (if any) */ if (this_find->next != NULL) { finder = this_find->next; this_find->next = finder->next; finder->next=list->next; list->next=finder; } } if (info.idx>=0) info.idx++; #if CORE_DEBUG ee_printf("List find %d: [%d,%d,%d]\n",i,retval,missed,found); #endif } retval+=found*4-missed; /* sort the list by data content and remove one item*/ if (finder_idx>0) list=core_list_mergesort(list,cmp_complex,res); remover=core_list_remove(list->next); /* CRC data content of list from location of index N forward, and then undo remove */ finder=core_list_find(list,&info); if (!finder) finder=list->next; while (finder) { retval=crc16(list->info->data16,retval); finder=finder->next; } #if CORE_DEBUG ee_printf("List sort 1: %04x\n",retval); #endif remover=core_list_undo_remove(remover,list->next); /* sort the list by index, in effect returning the list to original state */ list=core_list_mergesort(list,cmp_idx,NULL); /* CRC data content of list */ finder=list->next; while (finder) { retval=crc16(list->info->data16,retval); finder=finder->next; } #if CORE_DEBUG ee_printf("List sort 2: %04x\n",retval); #endif return retval; } /* Function: core_list_init Initialize list with data. Parameters: blksize - Size of memory to be initialized. memblock - Pointer to memory block. seed - Actual values chosen depend on the seed parameter. The seed parameter MUST be supplied from a source that cannot be determined at compile time Returns: Pointer to the head of the list. */ list_head *core_list_init(ee_u32 blksize, list_head *memblock, ee_s16 seed) { /* calculated pointers for the list */ ee_u32 per_item=16+sizeof(struct list_data_s); ee_u32 size=(blksize/per_item)-2; /* to accomodate systems with 64b pointers, and make sure same code is executed, set max list elements */ list_head *memblock_end=memblock+size; list_data *datablock=(list_data *)(memblock_end); list_data *datablock_end=datablock+size; /* some useful variables */ ee_u32 i; list_head *finder,*list=memblock; list_data info; /* create a fake items for the list head and tail */ list->next=NULL; list->info=datablock; list->info->idx=0x0000; list->info->data16=(ee_s16)0x8080; memblock++; datablock++; info.idx=0x7fff; info.data16=(ee_s16)0xffff; core_list_insert_new(list,&info,&memblock,&datablock,memblock_end,datablock_end); /* then insert size items */ for (i=0; inext; i=1; while (finder->next!=NULL) { if (iinfo->idx=i++; else { ee_u16 pat=(ee_u16)(i++ ^ seed); /* get a pseudo random number */ finder->info->idx=0x3fff & (((i & 0x07) << 8) | pat); /* make sure the mixed items end up after the ones in sequence */ } finder=finder->next; } list = core_list_mergesort(list,cmp_idx,NULL); #if CORE_DEBUG ee_printf("Initialized list:\n"); finder=list; while (finder) { ee_printf("[%04x,%04x]",finder->info->idx,(ee_u16)finder->info->data16); finder=finder->next; } ee_printf("\n"); #endif return list; } /* Function: core_list_insert Insert an item to the list Parameters: insert_point - where to insert the item. info - data for the cell. memblock - pointer for the list header datablock - pointer for the list data memblock_end - end of region for list headers datablock_end - end of region for list data Returns: Pointer to new item. */ list_head *core_list_insert_new(list_head *insert_point, list_data *info, list_head **memblock, list_data **datablock , list_head *memblock_end, list_data *datablock_end) { list_head *newitem; if ((*memblock+1) >= memblock_end) return NULL; if ((*datablock+1) >= datablock_end) return NULL; newitem=*memblock; (*memblock)++; newitem->next=insert_point->next; insert_point->next=newitem; newitem->info=*datablock; (*datablock)++; copy_info(newitem->info,info); return newitem; } /* Function: core_list_remove Remove an item from the list. Operation: For a singly linked list, remove by copying the data from the next item over to the current cell, and unlinking the next item. Note: since there is always a fake item at the end of the list, no need to check for NULL. Returns: Removed item. */ list_head *core_list_remove(list_head *item) { list_data *tmp; list_head *ret=item->next; /* swap data pointers */ tmp=item->info; item->info=ret->info; ret->info=tmp; /* and eliminate item */ item->next=item->next->next; ret->next=NULL; return ret; } /* Function: core_list_undo_remove Undo a remove operation. Operation: Since we want each iteration of the benchmark to be exactly the same, we need to be able to undo a remove. Link the removed item back into the list, and switch the info items. Parameters: item_removed - Return value from the item_modified - List item that was modified during Returns: The item that was linked back to the list. */ list_head *core_list_undo_remove(list_head *item_removed, list_head *item_modified) { list_data *tmp; /* swap data pointers */ tmp=item_removed->info; item_removed->info=item_modified->info; item_modified->info=tmp; /* and insert item */ item_removed->next=item_modified->next; item_modified->next=item_removed; return item_removed; } /* Function: core_list_find Find an item in the list Operation: Find an item by idx (if not 0) or specific data value Parameters: list - list head info - idx or data to find Returns: Found item, or NULL if not found. */ list_head *core_list_find(list_head *list,list_data *info) { if (info->idx>=0) { while (list && (list->info->idx != info->idx)) list=list->next; return list; } else { while (list && ((list->info->data16 & 0xff) != info->data16)) list=list->next; return list; } } /* Function: core_list_reverse Reverse a list Operation: Rearrange the pointers so the list is reversed. Parameters: list - list head info - idx or data to find Returns: Found item, or NULL if not found. */ list_head *core_list_reverse(list_head *list) { list_head *next=NULL, *tmp; while (list) { tmp=list->next; list->next=next; next=list; list=tmp; } return next; } /* Function: core_list_mergesort Sort the list in place without recursion. Description: Use mergesort, as for linked list this is a realistic solution. Also, since this is aimed at embedded, care was taken to use iterative rather then recursive algorithm. The sort can either return the list to original order (by idx) , or use the data item to invoke other other algorithms and change the order of the list. Parameters: list - list to be sorted. cmp - cmp function to use Returns: New head of the list. Note: We have a special header for the list that will always be first, but the algorithm could theoretically modify where the list starts. */ list_head *core_list_mergesort(list_head *list, list_cmp cmp, core_results *res) { list_head *p, *q, *e, *tail; ee_s32 insize, nmerges, psize, qsize, i; insize = 1; while (1) { p = list; list = NULL; tail = NULL; nmerges = 0; /* count number of merges we do in this pass */ while (p) { nmerges++; /* there exists a merge to be done */ /* step `insize' places along from p */ q = p; psize = 0; for (i = 0; i < insize; i++) { psize++; q = q->next; if (!q) break; } /* if q hasn't fallen off end, we have two lists to merge */ qsize = insize; /* now we have two lists; merge them */ while (psize > 0 || (qsize > 0 && q)) { /* decide whether next element of merge comes from p or q */ if (psize == 0) { /* p is empty; e must come from q. */ e = q; q = q->next; qsize--; } else if (qsize == 0 || !q) { /* q is empty; e must come from p. */ e = p; p = p->next; psize--; } else if (cmp(p->info,q->info,res) <= 0) { /* First element of p is lower (or same); e must come from p. */ e = p; p = p->next; psize--; } else { /* First element of q is lower; e must come from q. */ e = q; q = q->next; qsize--; } /* add the next element to the merged list */ if (tail) { tail->next = e; } else { list = e; } tail = e; } /* now p has stepped `insize' places along, and q has too */ p = q; } tail->next = NULL; /* If we have done only one merge, we're finished. */ if (nmerges <= 1) /* allow for nmerges==0, the empty list case */ return list; /* Otherwise repeat, merging lists twice the size */ insize *= 2; } #if COMPILER_REQUIRES_SORT_RETURN return list; #endif } /* Author : Shay Gal-On, EEMBC This file is part of EEMBC(R) and CoreMark(TM), which are Copyright (C) 2009 All rights reserved. EEMBC CoreMark Software is a product of EEMBC and is provided under the terms of the CoreMark License that is distributed with the official EEMBC COREMARK Software release. If you received this EEMBC CoreMark Software without the accompanying CoreMark License, you must discontinue use and download the official release from www.coremark.org. Also, if you are publicly displaying scores generated from the EEMBC CoreMark software, make sure that you are in compliance with Run and Reporting rules specified in the accompanying readme.txt file. EEMBC 4354 Town Center Blvd. Suite 114-200 El Dorado Hills, CA, 95762 */ /* File: core_main.c This file contains the framework to acquire a block of memory, seed initial parameters, tun t he benchmark and report the results. */ //#include "coremark.h" /* Function: iterate Run the benchmark for a specified number of iterations. Operation: For each type of benchmarked algorithm: a - Initialize the data block for the algorithm. b - Execute the algorithm N times. Returns: NULL. */ static ee_u16 list_known_crc[] = {(ee_u16)0xd4b0,(ee_u16)0x3340,(ee_u16)0x6a79,(ee_u16)0xe714,(ee_u16)0xe3c1}; static ee_u16 matrix_known_crc[] = {(ee_u16)0xbe52,(ee_u16)0x1199,(ee_u16)0x5608,(ee_u16)0x1fd7,(ee_u16)0x0747}; static ee_u16 state_known_crc[] = {(ee_u16)0x5e47,(ee_u16)0x39bf,(ee_u16)0xe5a4,(ee_u16)0x8e3a,(ee_u16)0x8d84}; void *iterate(void *pres) { ee_u32 i; ee_u16 crc; core_results *res=(core_results *)pres; ee_u32 iterations=res->iterations; res->crc=0; res->crclist=0; res->crcmatrix=0; res->crcstate=0; for (i=0; icrc=crcu16(crc,res->crc); crc=core_bench_list(res,-1); res->crc=crcu16(crc,res->crc); if (i==0) res->crclist=res->crc; } return NULL; } #if (SEED_METHOD==SEED_ARG) ee_s32 get_seed_args(int i, int argc, char *argv[]); #define get_seed(x) (ee_s16)get_seed_args(x,argc,argv) #define get_seed_32(x) get_seed_args(x,argc,argv) #else /* via function or volatile */ ee_s32 get_seed_32(int i); #define get_seed(x) (ee_s16)get_seed_32(x) #endif #if (MEM_METHOD==MEM_STATIC) ee_u8 static_memblk[TOTAL_DATA_SIZE]; #endif char *mem_name[3] = {"Static","Heap","Stack"}; /* Function: main Main entry routine for the benchmark. This function is responsible for the following steps: 1 - Initialize input seeds from a source that cannot be determined at compile time. 2 - Initialize memory block for use. 3 - Run and time the benchmark. 4 - Report results, testing the validity of the output if the seeds are known. Arguments: 1 - first seed : Any value 2 - second seed : Must be identical to first for iterations to be identical 3 - third seed : Any value, should be at least an order of magnitude less then the input size, but bigger then 32. 4 - Iterations : Special, if set to 0, iterations will be automatically determined such that the benchmark will run between 10 to 100 secs */ #if MAIN_HAS_NOARGC MAIN_RETURN_TYPE main(void) { int argc=0; char *argv[1]; #else MAIN_RETURN_TYPE main(int argc, char *argv[]) { #endif ee_u16 i,j=0,num_algorithms=0; ee_s16 known_id=-1,total_errors=0; ee_u16 seedcrc=0; CORE_TICKS total_time; core_results results[MULTITHREAD]; #if (MEM_METHOD==MEM_STACK) ee_u8 stack_memblock[TOTAL_DATA_SIZE*MULTITHREAD]; #endif /* first call any initializations needed */ portable_init(&(results[0].port), &argc, argv); /* First some checks to make sure benchmark will run ok */ if (sizeof(struct list_head_s)>128) { ee_printf("list_head structure too big for comparable data!\n"); return MAIN_RETURN_VAL; } results[0].seed1=get_seed(1); results[0].seed2=get_seed(2); results[0].seed3=get_seed(3); results[0].iterations=get_seed_32(4); #if CORE_DEBUG results[0].iterations=1; #endif results[0].execs=get_seed_32(5); if (results[0].execs==0) { /* if not supplied, execute all algorithms */ results[0].execs=ALL_ALGORITHMS_MASK; } /* put in some default values based on one seed only for easy testing */ if ((results[0].seed1==0) && (results[0].seed2==0) && (results[0].seed3==0)) { /* validation run */ results[0].seed1=0; results[0].seed2=0; results[0].seed3=0x66; } if ((results[0].seed1==1) && (results[0].seed2==0) && (results[0].seed3==0)) { /* perfromance run */ results[0].seed1=0x3415; results[0].seed2=0x3415; results[0].seed3=0x66; } #if (MEM_METHOD==MEM_STATIC) results[0].memblock[0]=(void *)static_memblk; results[0].size=TOTAL_DATA_SIZE; results[0].err=0; #if (MULTITHREAD>1) #error "Cannot use a static data area with multiple contexts!" #endif #elif (MEM_METHOD==MEM_MALLOC) for (i=0 ; i1) if (default_num_contexts>MULTITHREAD) { default_num_contexts=MULTITHREAD; } for (i=0 ; i=0) { for (i=0 ; i 0) ee_printf("Iterations/Sec : %f\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); #else ee_printf("Total time (secs): %d\n",time_in_secs(total_time)); if (time_in_secs(total_time) > 0) // ee_printf("Iterations/Sec : %d\n",default_num_contexts*results[0].iterations/time_in_secs(total_time)); ee_printf("Iterat/Sec/MHz : %d.%02d\n",1000*default_num_contexts*results[0].iterations/time_in_secs(total_time), 100000*default_num_contexts*results[0].iterations/time_in_secs(total_time) % 100); #endif if (time_in_secs(total_time) < 10) { ee_printf("ERROR! Must execute for at least 10 secs for a valid result!\n"); total_errors++; } ee_printf("Iterations : %u\n",(ee_u32)default_num_contexts*results[0].iterations); ee_printf("Compiler version : %s\n",COMPILER_VERSION); ee_printf("Compiler flags : %s\n",COMPILER_FLAGS); #if (MULTITHREAD>1) ee_printf("Parallel %s : %d\n",PARALLEL_METHOD,default_num_contexts); #endif ee_printf("Memory location : %s\n",MEM_LOCATION); /* output for verification */ ee_printf("seedcrc : 0x%04x\n",seedcrc); if (results[0].execs & ID_LIST) for (i=0 ; i1) ee_printf(" / %d:%s",default_num_contexts,PARALLEL_METHOD); #endif ee_printf("\n"); } #endif } if (total_errors>0) ee_printf("Errors detected\n"); if (total_errors<0) ee_printf("Cannot validate operation for these seed values, please compare with results on a known platform.\n"); #if (MEM_METHOD==MEM_MALLOC) for (i=0 ; i>(from)) & (~(0xffffffff << (to)))) #if CORE_DEBUG void printmat(MATDAT *A, ee_u32 N, char *name) { ee_u32 i,j; ee_printf("Matrix %s [%dx%d]:\n",name,N,N); for (i=0; i N times, changing the matrix values slightly by a constant amount each time. */ ee_u16 core_bench_matrix(mat_params *p, ee_s16 seed, ee_u16 crc) { ee_u32 N=p->N; MATRES *C=p->C; MATDAT *A=p->A; MATDAT *B=p->B; MATDAT val=(MATDAT)seed; crc=crc16(matrix_test(N,C,A,B,val),crc); return crc; } /* Function: matrix_test Perform matrix manipulation. Parameters: N - Dimensions of the matrix. C - memory for result matrix. A - input matrix B - operator matrix (not changed during operations) Returns: A CRC value that captures all results calculated in the function. In particular, crc of the value calculated on the result matrix after each step by . Operation: 1 - Add a constant value to all elements of a matrix. 2 - Multiply a matrix by a constant. 3 - Multiply a matrix by a vector. 4 - Multiply a matrix by a matrix. 5 - Add a constant value to all elements of a matrix. After the last step, matrix A is back to original contents. */ ee_s16 matrix_test(ee_u32 N, MATRES *C, MATDAT *A, MATDAT *B, MATDAT val) { ee_u16 crc=0; MATDAT clipval=matrix_big(val); matrix_add_const(N,A,val); /* make sure data changes */ #if CORE_DEBUG printmat(A,N,"matrix_add_const"); #endif matrix_mul_const(N,C,A,val); crc=crc16(matrix_sum(N,C,clipval),crc); #if CORE_DEBUG printmatC(C,N,"matrix_mul_const"); #endif matrix_mul_vect(N,C,A,B); crc=crc16(matrix_sum(N,C,clipval),crc); #if CORE_DEBUG printmatC(C,N,"matrix_mul_vect"); #endif matrix_mul_matrix(N,C,A,B); crc=crc16(matrix_sum(N,C,clipval),crc); #if CORE_DEBUG printmatC(C,N,"matrix_mul_matrix"); #endif matrix_mul_matrix_bitextract(N,C,A,B); crc=crc16(matrix_sum(N,C,clipval),crc); #if CORE_DEBUG printmatC(C,N,"matrix_mul_matrix_bitextract"); #endif matrix_add_const(N,A,-val); /* return matrix to initial value */ return crc; } /* Function : matrix_init Initialize the memory block for matrix benchmarking. Parameters: blksize - Size of memory to be initialized. memblk - Pointer to memory block. seed - Actual values chosen depend on the seed parameter. p - pointers to containing initialized matrixes. Returns: Matrix dimensions. Note: The seed parameter MUST be supplied from a source that cannot be determined at compile time */ ee_u32 core_init_matrix(ee_u32 blksize, void *memblk, ee_s32 seed, mat_params *p) { ee_u32 N=0; MATDAT *A; MATDAT *B; ee_s32 order=1; MATDAT val; ee_u32 i=0,j=0; if (seed==0) seed=1; while (jA=A; p->B=B; p->C=(MATRES *)align_mem(B+N*N); p->N=N; #if CORE_DEBUG printmat(A,N,"A"); printmat(B,N,"B"); #endif return N; } /* Function: matrix_sum Calculate a function that depends on the values of elements in the matrix. For each element, accumulate into a temporary variable. As long as this value is under the parameter clipval, add 1 to the result if the element is bigger then the previous. Otherwise, reset the accumulator and add 10 to the result. */ ee_s16 matrix_sum(ee_u32 N, MATRES *C, MATDAT clipval) { MATRES tmp=0,prev=0,cur=0; ee_s16 ret=0; ee_u32 i,j; for (i=0; iclipval) { ret+=10; tmp=0; } else { ret += (cur>prev) ? 1 : 0; } prev=cur; } } return ret; } /* Function: matrix_mul_const Multiply a matrix by a constant. This could be used as a scaler for instance. */ void matrix_mul_const(ee_u32 N, MATRES *C, MATDAT *A, MATDAT val) { ee_u32 i,j; for (i=0; i0) { for(i=0;i>3) & 0x3]; next=4; break; case 3: /* float */ case 4: /* float */ buf=floatpat[(seed>>3) & 0x3]; next=8; break; case 5: /* scientific */ case 6: /* scientific */ buf=scipat[(seed>>3) & 0x3]; next=8; break; case 7: /* invalid */ buf=errpat[(seed>>3) & 0x3]; next=8; break; default: /* Never happen, just to make some compilers happy */ break; } } size++; while (total='0') & (c<='9')) ? 1 : 0; return retval; } /* Function: core_state_transition Actual state machine. The state machine will continue scanning until either: 1 - an invalid input is detcted. 2 - a valid number has been detected. The input pointer is updated to point to the end of the token, and the end state is returned (either specific format determined or invalid). */ enum CORE_STATE core_state_transition( ee_u8 **instr , ee_u32 *transition_count) { ee_u8 *str=*instr; ee_u8 NEXT_SYMBOL; enum CORE_STATE state=CORE_START; for( ; *str && state != CORE_INVALID; str++ ) { NEXT_SYMBOL = *str; if (NEXT_SYMBOL==',') /* end of this input */ { str++; break; } switch(state) { case CORE_START: if(ee_isdigit(NEXT_SYMBOL)) { state = CORE_INT; } else if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { state = CORE_S1; } else if( NEXT_SYMBOL == '.' ) { state = CORE_FLOAT; } else { state = CORE_INVALID; transition_count[CORE_INVALID]++; } transition_count[CORE_START]++; break; case CORE_S1: if(ee_isdigit(NEXT_SYMBOL)) { state = CORE_INT; transition_count[CORE_S1]++; } else if( NEXT_SYMBOL == '.' ) { state = CORE_FLOAT; transition_count[CORE_S1]++; } else { state = CORE_INVALID; transition_count[CORE_S1]++; } break; case CORE_INT: if( NEXT_SYMBOL == '.' ) { state = CORE_FLOAT; transition_count[CORE_INT]++; } else if(!ee_isdigit(NEXT_SYMBOL)) { state = CORE_INVALID; transition_count[CORE_INT]++; } break; case CORE_FLOAT: if( NEXT_SYMBOL == 'E' || NEXT_SYMBOL == 'e' ) { state = CORE_S2; transition_count[CORE_FLOAT]++; } else if(!ee_isdigit(NEXT_SYMBOL)) { state = CORE_INVALID; transition_count[CORE_FLOAT]++; } break; case CORE_S2: if( NEXT_SYMBOL == '+' || NEXT_SYMBOL == '-' ) { state = CORE_EXPONENT; transition_count[CORE_S2]++; } else { state = CORE_INVALID; transition_count[CORE_S2]++; } break; case CORE_EXPONENT: if(ee_isdigit(NEXT_SYMBOL)) { state = CORE_SCIENTIFIC; transition_count[CORE_EXPONENT]++; } else { state = CORE_INVALID; transition_count[CORE_EXPONENT]++; } break; case CORE_SCIENTIFIC: if(!ee_isdigit(NEXT_SYMBOL)) { state = CORE_INVALID; transition_count[CORE_INVALID]++; } break; default: break; } } *instr=str; return state; } /* Author : Shay Gal-On, EEMBC This file is part of EEMBC(R) and CoreMark(TM), which are Copyright (C) 2009 All rights reserved. EEMBC CoreMark Software is a product of EEMBC and is provided under the terms of the CoreMark License that is distributed with the official EEMBC COREMARK Software release. If you received this EEMBC CoreMark Software without the accompanying CoreMark License, you must discontinue use and download the official release from www.coremark.org. Also, if you are publicly displaying scores generated from the EEMBC CoreMark software, make sure that you are in compliance with Run and Reporting rules specified in the accompanying readme.txt file. EEMBC 4354 Town Center Blvd. Suite 114-200 El Dorado Hills, CA, 95762 */ //#include "coremark.h" /* Function: get_seed Get a values that cannot be determined at compile time. Since different embedded systems and compilers are used, 3 different methods are provided: 1 - Using a volatile variable. This method is only valid if the compiler is forced to generate code that reads the value of a volatile variable from memory at run time. Please note, if using this method, you would need to modify core_portme.c to generate training profile. 2 - Command line arguments. This is the preferred method if command line arguments are supported. 3 - System function. If none of the first 2 methods is available on the platform, a system function which is not a stub can be used. e.g. read the value on GPIO pins connected to switches, or invoke special simulator functions. */ #if (SEED_METHOD==SEED_VOLATILE) extern volatile ee_s32 seed1_volatile; extern volatile ee_s32 seed2_volatile; extern volatile ee_s32 seed3_volatile; extern volatile ee_s32 seed4_volatile; extern volatile ee_s32 seed5_volatile; ee_s32 get_seed_32(int i) { ee_s32 retval; switch (i) { case 1: retval=seed1_volatile; break; case 2: retval=seed2_volatile; break; case 3: retval=seed3_volatile; break; case 4: retval=seed4_volatile; break; case 5: retval=seed5_volatile; break; default: retval=0; break; } return retval; } #elif (SEED_METHOD==SEED_ARG) ee_s32 parseval(char *valstring) { ee_s32 retval=0; ee_s32 neg=1; int hexmode=0; if (*valstring == '-') { neg=-1; valstring++; } if ((valstring[0] == '0') && (valstring[1] == 'x')) { hexmode=1; valstring+=2; } /* first look for digits */ if (hexmode) { while (((*valstring >= '0') && (*valstring <= '9')) || ((*valstring >= 'a') && (*valstring <= 'f'))) { ee_s32 digit=*valstring-'0'; if (digit>9) digit=10+*valstring-'a'; retval*=16; retval+=digit; valstring++; } } else { while ((*valstring >= '0') && (*valstring <= '9')) { ee_s32 digit=*valstring-'0'; retval*=10; retval+=digit; valstring++; } } /* now add qualifiers */ if (*valstring=='K') retval*=1024; if (*valstring=='M') retval*=1024*1024; retval*=neg; return retval; } ee_s32 get_seed_args(int i, int argc, char *argv[]) { if (argc>i) return parseval(argv[i]); return 0; } #elif (SEED_METHOD==SEED_FUNC) /* If using OS based function, you must define and implement the functions below in core_portme.h and core_portme.c ! */ ee_s32 get_seed_32(int i) { ee_s32 retval; switch (i) { case 1: retval=portme_sys1(); break; case 2: retval=portme_sys2(); break; case 3: retval=portme_sys3(); break; case 4: retval=portme_sys4(); break; case 5: retval=portme_sys5(); break; default: retval=0; break; } return retval; } #endif /* Function: crc* Service functions to calculate 16b CRC code. */ ee_u16 crcu8(ee_u8 data, ee_u16 crc ) { ee_u8 i=0,x16=0,carry=0; for (i = 0; i < 8; i++) { x16 = (ee_u8)((data & 1) ^ ((ee_u8)crc & 1)); data >>= 1; if (x16 == 1) { crc ^= 0x4002; carry = 1; } else carry = 0; crc >>= 1; if (carry) crc |= 0x8000; else crc &= 0x7fff; } return crc; } ee_u16 crcu16(ee_u16 newval, ee_u16 crc) { crc=crcu8( (ee_u8) (newval) ,crc); crc=crcu8( (ee_u8) ((newval)>>8) ,crc); return crc; } ee_u16 crcu32(ee_u32 newval, ee_u16 crc) { crc=crc16((ee_s16) newval ,crc); crc=crc16((ee_s16) (newval>>16) ,crc); return crc; } ee_u16 crc16(ee_s16 newval, ee_u16 crc) { return crcu16((ee_u16)newval, crc); } ee_u8 check_data_types() { ee_u8 retval=0; if (sizeof(ee_u8) != 1) { ee_printf("ERROR: ee_u8 is not an 8b datatype!\n"); retval++; } if (sizeof(ee_u16) != 2) { ee_printf("ERROR: ee_u16 is not a 16b datatype!\n"); retval++; } if (sizeof(ee_s16) != 2) { ee_printf("ERROR: ee_s16 is not a 16b datatype!\n"); retval++; } if (sizeof(ee_s32) != 4) { ee_printf("ERROR: ee_s32 is not a 32b datatype!\n"); retval++; } if (sizeof(ee_u32) != 4) { ee_printf("ERROR: ee_u32 is not a 32b datatype!\n"); retval++; } if (sizeof(ee_ptr_int) != sizeof(int *)) { ee_printf("ERROR: ee_ptr_int is not a datatype that holds an int pointer!\n"); retval++; } if (retval>0) { ee_printf("ERROR: Please modify the datatypes in core_portme.h!\n"); } return retval; } /* File : core_portme.c */ /* Author : Shay Gal-On, EEMBC Legal : TODO! */ #include #include //#include "coremark.h" #if VALIDATION_RUN volatile ee_s32 seed1_volatile=0x3415; volatile ee_s32 seed2_volatile=0x3415; volatile ee_s32 seed3_volatile=0x66; #endif #if PERFORMANCE_RUN volatile ee_s32 seed1_volatile=0x0; volatile ee_s32 seed2_volatile=0x0; volatile ee_s32 seed3_volatile=0x66; #endif #if PROFILE_RUN volatile ee_s32 seed1_volatile=0x8; volatile ee_s32 seed2_volatile=0x8; volatile ee_s32 seed3_volatile=0x8; #endif volatile ee_s32 seed4_volatile=ITERATIONS; volatile ee_s32 seed5_volatile=0; /* Porting : Timing functions How to capture time and convert to seconds must be ported to whatever is supported by the platform. e.g. Read value from on board RTC, read value from cpu clock cycles performance counter etc. Sample implementation for standard time.h and windows.h definitions included. */ /* Define : TIMER_RES_DIVIDER Divider to trade off timer resolution and total time that can be measured. Use lower values to increase resolution, but make sure that overflow does not occur. If there are issues with the return value overflowing, increase this value. */ //#define NSECS_PER_SEC CLOCKS_PER_SEC #define NSECS_PER_SEC 1000000000 #define CORETIMETYPE clock_t //#define GETMYTIME(_t) (*_t=clock()) #define GETMYTIME(_t) (*_t=0) #define MYTIMEDIFF(fin,ini) ((fin)-(ini)) #define TIMER_RES_DIVIDER 1 #define SAMPLE_TIME_IMPLEMENTATION 1 //#define EE_TICKS_PER_SEC (NSECS_PER_SEC / TIMER_RES_DIVIDER) #define EE_TICKS_PER_SEC 1000 /** Define Host specific (POSIX), or target specific global time variables. */ static CORETIMETYPE start_time_val, stop_time_val; /* Function : start_time This function will be called right before starting the timed portion of the benchmark. Implementation may be capturing a system timer (as implemented in the example code) or zeroing some system parameters - e.g. setting the cpu clocks cycles to 0. */ void start_time(void) { uint32_t mcyclel; asm volatile ("csrr %0,mcycle" : "=r" (mcyclel) ); start_time_val = mcyclel; } /* Function : stop_time This function will be called right after ending the timed portion of the benchmark. Implementation may be capturing a system timer (as implemented in the example code) or other system parameters - e.g. reading the current value of cpu cycles counter. */ void stop_time(void) { uint32_t mcyclel; asm volatile ("csrr %0,mcycle" : "=r" (mcyclel) ); stop_time_val = mcyclel; } /* Function : get_time Return an abstract "ticks" number that signifies time on the system. Actual value returned may be cpu cycles, milliseconds or any other value, as long as it can be converted to seconds by . This methodology is taken to accomodate any hardware or simulated platform. The sample implementation returns millisecs by default, and the resolution is controlled by */ CORE_TICKS get_time(void) { CORE_TICKS elapsed=(CORE_TICKS)(MYTIMEDIFF(stop_time_val, start_time_val)); return elapsed; } /* Function : time_in_secs Convert the value returned by get_time to seconds. The type is used to accomodate systems with no support for floating point. Default implementation implemented by the EE_TICKS_PER_SEC macro above. */ secs_ret time_in_secs(CORE_TICKS ticks) { secs_ret retval=((secs_ret)ticks) / (secs_ret)EE_TICKS_PER_SEC; return retval; } ee_u32 default_num_contexts=1; /* Function : portable_init Target specific initialization code Test for some common mistakes. */ void portable_init(core_portable *p, int *argc, char *argv[]) { if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) { ee_printf("ERROR! Please define ee_ptr_int to a type that holds a pointer!\n"); } if (sizeof(ee_u32) != 4) { ee_printf("ERROR! Please define ee_u32 to a 32b unsigned type!\n"); } p->portable_id=1; } /* Function : portable_fini Target specific final code */ void portable_fini(core_portable *p) { p->portable_id=0; } void* memset(void* s, int c, size_t n) { asm("mv t0, a0"); asm("add a2, a2, a0"); // end = s + n asm(".memset_loop: bge a0, a2, .memset_end"); asm("sb a1, 0(a0)"); asm("addi a0, a0, 1"); asm("j .memset_loop"); asm(".memset_end:"); asm("mv a0, t0"); asm("jr ra"); } ================================================ FILE: testbench/asm/cmark.mki ================================================ TEST_CFLAGS = -finline-limit=400 -mbranch-cost=1 -Ofast -fno-code-hoisting -funroll-all-loops OFILES = crt0.o printf.o cmark.o ================================================ FILE: testbench/asm/cmark_iccm.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000 ; .text : { crt0.o (.text*) } _end = .; . = 0xee000000 ; .text.init : { cmark.o (.text*) } . = 0xd0580000; .data.io . : { *(.data.io) } . = 0xf0040000; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xfffffff0; .iccm.ctl : { LONG(0xee000000); LONG(0xee008000) } . = 0xfffffff8; .data.ctl : { LONG(0xf0040000); LONG(STACK) } } ================================================ FILE: testbench/asm/cmark_iccm.mki ================================================ TEST_CFLAGS = -g -O3 -funroll-all-loops OFILES = crt0.o printf.o cmark.o ================================================ FILE: testbench/asm/common.s ================================================ #include "defines.h" #include "tb.h" .section .text .global _start _start: // Clear minstret csrw minstret, zero csrw minstreth, zero // Enable Caches in MRAC li x2, 0x5f555555 csrw 0x7c0, x2 // global interrupt enable csrr x2, mstatus ori x2, x2, 0x8 csrw mstatus, x2 // set up mtvec la x2, exc_int_handler csrw mtvec, x2 // Set up NMI handler address li x3, STDOUT ori x2, x2, LOAD_NMI_ADDR sw x2, 0(x3) j main // Write 0xff to STDOUT for TB to terminate test. _finish: li x3, STDOUT addi x5, x0, 0xff sb x5, 0(x3) beq x0, x0, _finish .rept 100 nop .endr // handler must be aligned to 256 bytes since it has to fit // in the upper 24 bits of nmi handler address set testbench command .balign 256 exc_int_handler: // disable all interrupt sources csrw mie, zero // reenable signaling of NMIs for subsequent NMIs csrw 0xBC0, zero // mdeau // compare CSRs with expected values csrr x2, mcause bne x2, x4, fail csrr x2, 0x7FF // mscause bne x2, x5, fail // set mepc to return from the test once we leave the handler la x2, ok csrw mepc, x2 mret // used for making sure we fail if we didn't jump to the exception/NMI handler fail_if_not_serviced: .rept 15 nop .endr // fail if interrupt didn't get serviced j fail fail: // write 0x01 to STDOUT for TB to fail the test li x3, STDOUT addi x5, x0, 0x01 sb x5, 0(x3) j fail ok: ret ================================================ FILE: testbench/asm/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 # Copyright 2020 Western Digital Corporation or its affiliates. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # // startup code to support HLL programs #include "defines.h" .section .text.init .align 4 .global _start _start: // Set trap handler la x1, _trap csrw mtvec, x1 // enable caching, except region 0xd li t0, 0x59555555 csrw 0x7c0, t0 la sp, STACK call main # Map exit code of main() to command to be written to tohost snez a0, a0 bnez a0, _finish li a0, 0xFF .global _finish _finish: la t0, tohost sb a0, 0(t0) // DemoTB test termination li a0, 1 sw a0, 0(t0) // Whisper test termination beq x0, x0, _finish .rept 10 nop .endr .align 4 _trap: li a0, 1 # failure j _finish .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/asm/dbus_nonblocking_load_error.s ================================================ #include "common.s" dbus_nonblocking_load_error: li x4, 0xF0000001 li x5, 0x0 // trigger bus fault at next load li x2, TRIGGER_DBUS_FAULT li x3, STDOUT sw x2, 0(x3) // bus fault is triggered on this instruction lw x2, 0(zero) j fail_if_not_serviced main: call dbus_nonblocking_load_error j _finish ================================================ FILE: testbench/asm/dbus_store_error.s ================================================ #include "common.s" dbus_store_error: li x4, 0xF0000000 li x5, 0x0 // address of some data that resides in memory (and not in iccm/dccm) lw x6, _start // trigger bus fault at next store li x2, TRIGGER_DBUS_FAULT li x3, STDOUT sw x2, 0(x3) // bus fault is triggered on this instruction sw x2, 0(x6) j fail_if_not_serviced main: call dbus_store_error j _finish ================================================ FILE: testbench/asm/dside_access_across_region_boundary.s ================================================ #include "common.s" dside_load_across_region_boundary: li x4, 0x4 li x5, 0x2 // load from across region boundary li x2, 0xe0000000-2 lw x2, 0(x2) j fail_if_not_serviced dside_store_across_region_boundary: li x4, 0x6 li x5, 0x2 // store across region boundary li x2, 0xe0000000-2 sw x2, 0(x2) j fail_if_not_serviced main: call dside_load_across_region_boundary call dside_store_across_region_boundary j _finish ================================================ FILE: testbench/asm/dside_access_region_prediction_error.s ================================================ #include "common.s" dside_load_region_prediction_error: li x4, 0x5 li x5, 0x5 // We take a large address that will overflow to another region // when offset is used in an 'lw' instruction: 0xFFFFFFFC + 0x4 li x2, 0xFFFFFFFC lw x2, 0x4(x2) j fail_if_not_serviced dside_store_region_prediction_error: li x4, 0x7 li x5, 0x5 // same as in load region prediction error li x2, 0xFFFFFFFC sw x2, 0x4(x2) j fail_if_not_serviced main: call dside_load_region_prediction_error call dside_store_region_prediction_error j _finish ================================================ FILE: testbench/asm/dside_core_local_access_unmapped_address_error.s ================================================ #include "common.s" dside_core_local_load_unmapped_address_error: li x4, 0x5 li x5, 0x2 // load from DCCM upper boundary (this also triggers unmapped address error) li x2, RV_DCCM_EADR - 1 lw x2, 0(x2) j fail_if_not_serviced dside_core_local_store_unmapped_address_error: li x4, 0x7 li x5, 0x2 // store to DCCM upper boundary (this also triggers unmapped address error) li x2, RV_DCCM_EADR - 1 sw x2, 0(x2) j fail_if_not_serviced main: call dside_core_local_load_unmapped_address_error call dside_core_local_store_unmapped_address_error j _finish ================================================ FILE: testbench/asm/dside_pic_access_error.s ================================================ #include "common.s" dside_pic_load_access_error: li x4, 0x5 li x5, 0x6 // perform not word-sized load from PIC li x2, RV_PIC_BASE_ADDR lb x2, 0(x2) j fail_if_not_serviced dside_pic_store_access_error: li x4, 0x7 li x5, 0x6 // perform not word-sized store to PIC li x2, RV_PIC_BASE_ADDR sb x2, 0(x2) j fail_if_not_serviced main: call dside_pic_load_access_error call dside_pic_store_access_error j _finish ================================================ FILE: testbench/asm/dside_size_misaligned_access_to_non_idempotent_address.s ================================================ #include "common.s" dside_size_misaligned_load_to_non_idempotent_address: li x4, 0x4 li x5, 0x1 // load from across non-idempotent address (with side effects) // we take advantage of the fact that STDOUT is such an address li x2, STDOUT-2 lw x2, 0(x2) j fail_if_not_serviced dside_size_misaligned_store_to_non_idempotent_address: li x4, 0x6 li x5, 0x1 // store to across non-idempotent address (with side effect) // we take advantage of the fact that STDOUT is such an address li x2, STDOUT-2 sw x2, 0(x2) j fail_if_not_serviced main: call dside_size_misaligned_load_to_non_idempotent_address call dside_size_misaligned_store_to_non_idempotent_address j _finish ================================================ FILE: testbench/asm/ebreak_ecall.s ================================================ #include "common.s" breakpoint_ebreak: li x4, 0x3 li x5, 0x2 ebreak j fail_if_not_serviced environment_call_from_m_mode: li x4, 0xB li x5, 0x0 ecall j fail_if_not_serviced main: call breakpoint_ebreak call environment_call_from_m_mode j _finish ================================================ FILE: testbench/asm/hello_world.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text*) } _end = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/asm/hello_world.s ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2019 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Assembly code for Hello World // Not using only ALU ops for creating the string #include "defines.h" #define STDOUT 0xd0580000 // Code to execute .section .text .global _start _start: // Clear minstret csrw minstret, zero csrw minstreth, zero // Set trap handler la x1, _trap csrw mtvec, x1 // Enable Caches in MRAC li x1, 0x5f555555 csrw 0x7c0, x1 // Load string from hw_data // and write to stdout address li x3, STDOUT la x4, hw_data loop: lb x5, 0(x4) sb x5, 0(x3) addi x4, x4, 1 bnez x5, loop li a0, 0xff # success // Write return value (a0) from printf to STDOUT for TB to termiate test. _finish: li x3, STDOUT sb a0, 0(x3) beq x0, x0, _finish .rept 100 nop .endr .align 4 _trap: li a0, 1 # failure j _finish .data hw_data: .ascii "-------------------------\n" .ascii "Hello World from VeeR EL2\n" .ascii "-------------------------\n" .byte 0 ================================================ FILE: testbench/asm/hello_world_dccm.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text*) } _end = .; . = 0xd0580000; .data.io . : { *(.data.io) } . = 0xf0040000; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xfffffff8; .data.ctl : { LONG(0xf0040000); LONG(STACK) } } ================================================ FILE: testbench/asm/hello_world_iccm.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text*) } .data : { *(.*data) *(.rodata*)} . = ALIGN(4); printf_start = .; . = 0xee000000; .data_load : AT(printf_start) {*(.data_text)} printf_end = printf_start + SIZEOF(.data_load); } ================================================ FILE: testbench/asm/hello_world_iccm.s ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2019 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Assembly code for Hello World // Not using only ALU ops for creating the string #include "defines.h" #define STDOUT 0xd0580000 .set mfdc, 0x7f9 .extern printf_start, printf_end // Code to execute .section .text .align 4 .global _start _start: // Set trap handler la x1, _trap csrw mtvec, x1 // Enable Caches in MRAC li x1, 0x5f555555 csrw 0x7c0, x1 li x3, 4 csrw mfdc, x3 // disable store merging li x3, RV_ICCM_SADR la x4, printf_start la x5, printf_end load: lw x6, 0 (x4) sw x6, 0 (x3) addi x4,x4,4 addi x3,x3,4 bltu x4, x5, load fence.i call printf // Write return value (a0) from printf to STDOUT for TB to termiate test. _finish: li x3, STDOUT sb a0, 0(x3) beq x0, x0, _finish .rept 100 nop .endr .align 4 _trap: li a0, 1 # failure j _finish .data hw_data: .ascii "------------------------------\n" .ascii "Hello World from VeeR EL2 ICCM\n" .ascii "------------------------------\n" .byte 0 .section .data_text, "ax" // Load string from hw_data // and write to stdout address printf: li x3, STDOUT la x4, hw_data loop: lb x5, 0(x4) sb x5, 0(x3) addi x4, x4, 1 bnez x5, loop li a0, 0xff # success ret .long 0,1,2,3,4 ================================================ FILE: testbench/asm/icache.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { .text : { *(.text*) } . = 0x10000; .data : { *(.*data) *(.rodata*)} } ================================================ FILE: testbench/asm/icache.s ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "defines.h" #define STDOUT 0xd0580000 .set mfdc, 0x7f9 .set mrac, 0x7c0 // Code to execute .section .text .global _start _start: // Enable Caches in MRAC li x1, 0x5f555555 csrw mrac, x1 li x3, 4 csrw mfdc, x3 // disable store merging li t3, 0 // counter for the outer loop li t5, 100 // limit the outer loop to 100 iterations outer: beq t3, t5, report_success addi t3, t3, 1 li t4, 123 inner: addi t4, t4, -1 bne t4, zero, inner jal x0, outer report_success: // write 0xff to STDOUT to report success li x3, STDOUT li x2, 0xff sw x2, 0(x3) end: nop j end .long 0,1,2,3,4 ================================================ FILE: testbench/asm/illegal_instruction.s ================================================ #include "common.s" illegal_instruction: li x4, 0x2 li x5, 0x0 .word 0 j fail_if_not_serviced main: call illegal_instruction j _finish ================================================ FILE: testbench/asm/infinite_loop.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { .text : { *(.text*) } . = 0x10000; .data : { *(.*data) *(.rodata*)} . = ALIGN(4); printf_start = .; . = 0xee000000; .data_load : AT(printf_start) {*(.data_text)} printf_end = printf_start + SIZEOF(.data_load); } ================================================ FILE: testbench/asm/infinite_loop.s ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2019 Western Digital Corporation or its affiliates. // Copyright 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Copied hello_world_iccm with an infinite loop inserted at the end #include "defines.h" #define STDOUT 0xd0580000 .set mfdc, 0x7f9 .extern printf_start, printf_end // Code to execute .section .text .global _start _start: // Enable Caches in MRAC li x1, 0x5f555555 csrw 0x7c0, x1 li x3, 4 csrw mfdc, x3 // disable store merging // Simple infinite loop program with inner and outer loop li t3, 0 outer: addi t3, t3, 1 li t4, 123 inner: addi t4, t4, -1 bne t4, zero, inner jal x0, outer .long 0,1,2,3,4 ================================================ FILE: testbench/asm/internal_timer_ints.s ================================================ #include "common.s" machine_internal_timer0_local_interrupt: li x4, 0x8000001d li x5, 0x0 csrw 0x7D4, 0x0 // disable incrementing timer0 csrw 0x7D2, 0x0 // reset timer0 count value csrw 0x7D3, 0x8 // set timer0 threshold to 8 li x2, 0x20000000 csrw mie, x2 // enable timer0 local interrupt csrw 0x7D4, 0x1 // reenable incrementing timer0 j fail_if_not_serviced machine_internal_timer1_local_interrupt: li x4, 0x8000001c li x5, 0x0 csrw 0x7D7, 0x0 // disable incrementing timer0 csrw 0x7D5, 0x0 // reset timer0 count value csrw 0x7D6, 0x8 // set timer0 threshold to 8 li x2, 0x10000000 csrw mie, x2 // enable timer0 local interrupt csrw 0x7D7, 0x1 // reenable incrementing timer0 j fail_if_not_serviced main: call machine_internal_timer0_local_interrupt call machine_internal_timer1_local_interrupt j _finish ================================================ FILE: testbench/asm/iside_core_local_unmapped_address_error.s ================================================ #include "common.s" iside_core_local_unmapped_address_error: li x4, 0x1 li x5, 0x2 // jump to address that's only halfway inside ICCM li x2, 0xee000000-2 jalr x2, 0(x2) j fail_if_not_serviced main: call iside_core_local_unmapped_address_error j _finish ================================================ FILE: testbench/asm/iside_fetch_precise_bus_error.s ================================================ #include "common.s" iside_fetch_precise_bus_error: li x4, 0x1 li x5, 0x9 li x2, TRIGGER_IBUS_FAULT li x3, STDOUT sw x2, 0(x3) // ibus fault is triggered on subsequent instruction - force refetch from memory // since testbench relies on bus transaction happening to trigger bus error fence.i j fail_if_not_serviced main: call iside_fetch_precise_bus_error j _finish ================================================ FILE: testbench/asm/lsu_trigger_hit.s ================================================ #include "common.s" lsu_trigger_hit: la x4, 0x3 la x5, 0x1 // set up address to trigger on li x2, 0xdeadbeef csrw tdata2, x2 // enable trigger in M-mode, fire on address of a load li x3, 0x41 csrw mcontrol, x3 // load from that address lw x2, 0(x2) j fail_if_not_serviced main: call lsu_trigger_hit j _finish ================================================ FILE: testbench/asm/machine_external_ints.s ================================================ #include "common.s" machine_software_interrupt: la x4, 0x80000003 li x5, 0x0 // enable software interrupt li x2, 0x8 csrw mie, x2 // trigger soft interrupt li x2, TRIGGER_SOFT_INT li x3, STDOUT sw x2, 0(x3) j fail_if_not_serviced machine_timer_interrupt: la x4, 0x80000007 li x5, 0x0 // enable machine timer interrupt li x2, 0x80 csrw mie, x2 // trigger timer interrupt li x2, TRIGGER_TIMER_INT li x3, STDOUT sw x2, 0(x3) j fail_if_not_serviced main: call machine_software_interrupt call machine_timer_interrupt j _finish ================================================ FILE: testbench/asm/machine_external_vec_ints.s ================================================ #include "common.s" enable_ext_int1: // set up gateway configuration - level triggered active high li x2, 0x0 li x3, (RV_PIC_BASE_ADDR + 0x4004) // meigwctrl1 sw x2, 0(x3) // clear interrupt bit for gateway li x3, (RV_PIC_BASE_ADDR + 0x5004) // meigwclr1 sw zero, 0(x3) // set up priority level li x3, (RV_PIC_BASE_ADDR + 0x4) // meipl1 li x2, 0x1 sw x2, 0(x3) // interrupt priority threshold and priority nesting are // already initialized at correct value and we're only // testing one interrupt so we don't bother setting them explicitly // enable external interrupt 1 li x3, (RV_PIC_BASE_ADDR + 0x2004) li x2, 0x1 sw x2, 0(x3) // enable external interrupts li x2, 0x800 csrw mie, x2 ret machine_external_interrupt: la x4, 0x8000000b la x5, 0x0 // Set up external interrupt vector table at the beginning of DCCM la x2, exc_int_handler li x3, RV_DCCM_SADR sw x2, 0(x3) // set up base interrupt vector table address csrw 0xBC8, x3 // meivt mv x6, x1 // save return address call enable_ext_int1 mv x1, x6 // restore return address li x2, TRIGGER_EXT_INT1 li x3, STDOUT sw x2, 0(x3) j fail_if_not_serviced fast_interrupt_dccm_region_access_error: la x4, 0xF0001001 la x5, 0x0 // set up base interrupt vector table address at some address // *not* in DCCM but in DCCM region // assume somewhat optimistically that DCCM isn't allocated // at the end of its region so RV_DCCM_EADR + 1 is still in DCCM region li x2, RV_DCCM_EADR + 1 csrw 0xBC8, x2 // meivt mv x6, x1 // save return address call enable_ext_int1 mv x1, x6 // restore return address // trigger external interrupt 1 li x2, TRIGGER_EXT_INT1 li x3, STDOUT sw x2, 0(x3) j fail_if_not_serviced fast_interrupt_non_dccm_region: la x4, 0xF0001002 la x5, 0x0 // set up interrupt vector table address at an address that's // not in DCCM region li x2, ((RV_DCCM_REGION + 1) % 0x10) << 28 csrw 0xBC8, x2 // meivt mv x6, x1 // save return address call enable_ext_int1 mv x1, x6 // restore return address // trigger external interrupt 1 li x2, TRIGGER_EXT_INT1 li x3, STDOUT sw x2, 0(x3) j fail_if_not_serviced main: call machine_external_interrupt call fast_interrupt_dccm_region_access_error call fast_interrupt_non_dccm_region j _finish ================================================ FILE: testbench/asm/nmi_pin_assertion.s ================================================ #include "common.s" nmi_pin_assertion: li x4, 0x0 li x5, 0x0 // trigger NMI li x2, TRIGGER_NMI li x3, STDOUT sw x2, 0(x3) j fail_if_not_serviced main: call nmi_pin_assertion j _finish ================================================ FILE: testbench/asm/printf.c ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include #include extern volatile char tohost; static int whisperPutc(char c) { tohost = c; return c; } static int whisperPuts(const char* s) { while (*s) whisperPutc(*s++); whisperPutc('\n'); // whisperPutc(0xd); return 1; } static int whisperPrintUnsigned(unsigned value, int width, char pad) { char buffer[20]; int charCount = 0; do { char c = '0' + (value % 10); value = value / 10; buffer[charCount++] = c; } while (value); for (int i = charCount; i < width; ++i) whisperPutc(pad); char* p = buffer + charCount - 1; for (int i = 0; i < charCount; ++i) whisperPutc(*p--); return charCount; } static int whisperPrintDecimal(int value, int width, char pad) { char buffer[20]; int charCount = 0; unsigned neg = value < 0; if (neg) { value = -value; whisperPutc('-'); width--; } do { char c = '0' + (value % 10); value = value / 10; buffer[charCount++] = c; } while (value); for (int i = charCount; i < width; ++i) whisperPutc(pad); char* p = buffer + charCount - 1; for (int i = 0; i < charCount; ++i) whisperPutc(*p--); if (neg) charCount++; return charCount; } static int whisperPrintInt(int value, int width, int pad, int base) { if (base == 10) return whisperPrintDecimal(value, width, pad); char buffer[20]; int charCount = 0; unsigned uu = value; if (base == 8) { do { char c = '0' + (uu & 7); buffer[charCount++] = c; uu >>= 3; } while (uu); } else if (base == 16) { do { int digit = uu & 0xf; char c = digit < 10 ? '0' + digit : 'a' + digit - 10; buffer[charCount++] = c; uu >>= 4; } while (uu); } else return -1; char* p = buffer + charCount - 1; for (unsigned i = 0; i < charCount; ++i) whisperPutc(*p--); return charCount; } /* // Print with g format static int whisperPrintDoubleG(double value) { return 0; } // Print with f format static int whisperPrintDoubleF(double value) { return 0; } */ int whisperPrintfImpl(const char* format, va_list ap) { int count = 0; // Printed character count for (const char* fp = format; *fp; fp++) { char pad = ' '; int width = 0; // Field width if (*fp != '%') { whisperPutc(*fp); ++count; continue; } ++fp; // Skip % if (*fp == 0) break; if (*fp == '%') { whisperPutc('%'); continue; } while (*fp == '0') { pad = '0'; fp++; // Pad zero not yet implented. } if (*fp == '-') { fp++; // Pad right not yet implemented. } if (*fp == '*') { int outWidth = va_arg(ap, int); fp++; // Width not yet implemented. } else if (*fp >= '0' && *fp <= '9') { // Width not yet implemented. while (*fp >= '0' && *fp <= '9') width = width * 10 + (*fp++ - '0'); } switch (*fp) { case 'd': count += whisperPrintDecimal(va_arg(ap, int), width, pad); break; case 'u': count += whisperPrintUnsigned((unsigned) va_arg(ap, unsigned), width, pad); break; case 'x': case 'X': count += whisperPrintInt(va_arg(ap, int), width, pad, 16); break; case 'o': count += whisperPrintInt(va_arg(ap, int), width, pad, 8); break; case 'c': whisperPutc(va_arg(ap, int)); ++count; break; case 's': count += whisperPuts(va_arg(ap, char*)); break; /* case 'g': count += whisperPrintDoubleG(va_arg(ap, double)); break; case 'f': count += whisperPrintDoubleF(va_arg(ap, double)); */ } } return count; } int whisperPrintf(const char* format, ...) { va_list ap; va_start(ap, format); int code = whisperPrintfImpl(format, ap); va_end(ap); return code; } int putchar(int c) { return whisperPutc(c); } struct FILE; int putc(int c, struct FILE* f) { return whisperPutc(c); } int puts(const char* s) { return whisperPuts(s); } int printf(const char* format, ...) { va_list ap; va_start(ap, format); int code = whisperPrintfImpl(format, ap); va_end(ap); return code; } // function to read cpu mcycle csr for performance measurements // simplified version uint64_t get_mcycle(){ unsigned int mcyclel; unsigned int mcycleh0 = 0, mcycleh1=1; uint64_t cycles; while(mcycleh0 != mcycleh1) { asm volatile ("csrr %0,mcycleh" : "=r" (mcycleh0) ); asm volatile ("csrr %0,mcycle" : "=r" (mcyclel) ); asm volatile ("csrr %0,mcycleh" : "=r" (mcycleh1) ); } cycles = mcycleh1; return (cycles << 32) | mcyclel; } ================================================ FILE: testbench/asm/read_after_read.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text*) } _end = .; . = 0xc0000000; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/asm/read_after_read.mki ================================================ TEST_CFLAGS = -g -O3 -falign-functions=16 OFILES = crt0.o read_after_read.o ================================================ FILE: testbench/asm/read_after_read.s ================================================ #include "defines.h" .set mfdc, 0x7f9 .section .text .align 4 .global main main: // Clear minstret csrw minstret, zero csrw minstreth, zero li t0, 0x5A555555 csrw 0x7c0, t0 li t0, 4 fence.i csrw mfdc, t0 // disable store merging fence.i la a0, scratchpad la s6, scratchpad lw zero, 304(a0) lw a0, 24(s6) // 0x18 lw a1, 20(s6) // 0x14 sw a0, 28(sp) sw a1, 24(sp) lw a0, 16(s6) // 0x10 lw a1, 12(s6) // 0x_C lw s3, 4(s6) // 0x_4 lw s8, 8(s6) // 0x_8 sw a0, 20(sp) sw a1, 16(sp) sw s3, 12(sp) sw s8, 8(sp) li a0, 1 lw a1, 28(sp) li t0, 6 bne a1, t0, failed lw a1, 24(sp) li t0, 5 bne a1, t0, failed lw a1, 20(sp) li t0, 4 bne a1, t0, failed lw a1, 16(sp) li t0, 3 bne a1, t0, failed lw a1, 12(sp) li t0, 1 bne a1, t0, failed lw a1, 8(sp) li t0, 2 bne a1, t0, failed lw a1, 4(sp) li t0, 0 bne a1, t0, failed li a0, 0 .global failed failed: ret .section .data .global scratchpad scratchpad: .4byte 0 .4byte 1 .4byte 2 .4byte 3 .4byte 4 .4byte 5 .4byte 6 .4byte 7 .4byte 8 .4byte 9 .4byte 10 .4byte 11 .4byte 12 .4byte 13 .4byte 14 .4byte 15 .4byte 16 .4byte 17 .4byte 18 .4byte 19 .4byte 20 .4byte 21 .4byte 22 .4byte 23 .4byte 24 .4byte 25 .4byte 26 .4byte 27 .4byte 28 .4byte 29 .4byte 30 .4byte 31 .4byte 32 .4byte 33 .4byte 34 .4byte 35 .4byte 36 .4byte 37 .4byte 38 .4byte 39 .4byte 40 .4byte 41 .4byte 42 .4byte 43 .4byte 44 .4byte 45 .4byte 46 .4byte 47 .4byte 48 .4byte 49 .4byte 50 .4byte 51 .4byte 52 .4byte 53 .4byte 54 .4byte 55 .4byte 56 .4byte 57 .4byte 58 .4byte 59 .4byte 60 .4byte 61 .4byte 62 .4byte 63 .4byte 64 .4byte 65 .4byte 66 .4byte 67 .4byte 68 .4byte 69 .4byte 70 .4byte 71 .4byte 72 .4byte 73 .4byte 74 .4byte 75 .4byte 76 ================================================ FILE: testbench/asm/tb.h ================================================ #define STDOUT 0xd0580000 #define TRIGGER_NMI 0x80 #define LOAD_NMI_ADDR 0x81 #define TRIGGER_SOFT_INT 0x84 #define TRIGGER_TIMER_INT 0x85 #define TRIGGER_EXT_INT1 0x86 #define TRIGGER_DBUS_FAULT 0x87 #define TRIGGER_IBUS_FAULT 0x88 ================================================ FILE: testbench/axi4_mux/arbiter.v ================================================ /* Copyright (c) 2014-2021 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * Arbiter module */ module arbiter # ( parameter PORTS = 4, // select round robin arbitration parameter ARB_TYPE_ROUND_ROBIN = 0, // blocking arbiter enable parameter ARB_BLOCK = 0, // block on acknowledge assert when nonzero, request deassert when 0 parameter ARB_BLOCK_ACK = 1, // LSB priority selection parameter ARB_LSB_HIGH_PRIORITY = 0 ) ( input wire clk, input wire rst, input wire [PORTS-1:0] request, input wire [PORTS-1:0] acknowledge, output wire [PORTS-1:0] grant, output wire grant_valid, output wire [$clog2(PORTS)-1:0] grant_encoded ); reg [PORTS-1:0] grant_reg = 0, grant_next; reg grant_valid_reg = 0, grant_valid_next; reg [$clog2(PORTS)-1:0] grant_encoded_reg = 0, grant_encoded_next; assign grant_valid = grant_valid_reg; assign grant = grant_reg; assign grant_encoded = grant_encoded_reg; wire request_valid; wire [$clog2(PORTS)-1:0] request_index; wire [PORTS-1:0] request_mask; priority_encoder #( .WIDTH(PORTS), .LSB_HIGH_PRIORITY(ARB_LSB_HIGH_PRIORITY) ) priority_encoder_inst ( .input_unencoded(request), .output_valid(request_valid), .output_encoded(request_index), .output_unencoded(request_mask) ); reg [PORTS-1:0] mask_reg = 0, mask_next; wire masked_request_valid; wire [$clog2(PORTS)-1:0] masked_request_index; wire [PORTS-1:0] masked_request_mask; priority_encoder #( .WIDTH(PORTS), .LSB_HIGH_PRIORITY(ARB_LSB_HIGH_PRIORITY) ) priority_encoder_masked ( .input_unencoded(request & mask_reg), .output_valid(masked_request_valid), .output_encoded(masked_request_index), .output_unencoded(masked_request_mask) ); always @* begin grant_next = 0; grant_valid_next = 0; grant_encoded_next = 0; mask_next = mask_reg; if (ARB_BLOCK && !ARB_BLOCK_ACK && grant_reg & request) begin // granted request still asserted; hold it grant_valid_next = grant_valid_reg; grant_next = grant_reg; grant_encoded_next = grant_encoded_reg; end else if (ARB_BLOCK && ARB_BLOCK_ACK && grant_valid && !(grant_reg & acknowledge)) begin // granted request not yet acknowledged; hold it grant_valid_next = grant_valid_reg; grant_next = grant_reg; grant_encoded_next = grant_encoded_reg; end else if (request_valid) begin if (ARB_TYPE_ROUND_ROBIN) begin if (masked_request_valid) begin grant_valid_next = 1; grant_next = masked_request_mask; grant_encoded_next = masked_request_index; if (ARB_LSB_HIGH_PRIORITY) begin mask_next = {PORTS{1'b1}} << (masked_request_index + 1); end else begin mask_next = {PORTS{1'b1}} >> (PORTS - masked_request_index); end end else begin grant_valid_next = 1; grant_next = request_mask; grant_encoded_next = request_index; if (ARB_LSB_HIGH_PRIORITY) begin mask_next = {PORTS{1'b1}} << (request_index + 1); end else begin mask_next = {PORTS{1'b1}} >> (PORTS - request_index); end end end else begin grant_valid_next = 1; grant_next = request_mask; grant_encoded_next = request_index; end end end always @(posedge clk) begin if (rst) begin grant_reg <= 0; grant_valid_reg <= 0; grant_encoded_reg <= 0; mask_reg <= 0; end else begin grant_reg <= grant_next; grant_valid_reg <= grant_valid_next; grant_encoded_reg <= grant_encoded_next; mask_reg <= mask_next; end end endmodule `resetall ================================================ FILE: testbench/axi4_mux/axi_crossbar.v ================================================ /* Copyright (c) 2018 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * AXI4 crossbar */ module axi_crossbar # ( // Number of AXI inputs (slave interfaces) parameter S_COUNT = 4, // Number of AXI outputs (master interfaces) parameter M_COUNT = 4, // Width of data bus in bits parameter DATA_WIDTH = 32, // Width of address bus in bits parameter ADDR_WIDTH = 32, // Width of wstrb (width of data bus in words) parameter STRB_WIDTH = (DATA_WIDTH/8), // Input ID field width (from AXI masters) parameter S_ID_WIDTH = 8, // Output ID field width (towards AXI slaves) // Additional bits required for response routing parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT), // Propagate awuser signal parameter AWUSER_ENABLE = 0, // Width of awuser signal parameter AWUSER_WIDTH = 1, // Propagate wuser signal parameter WUSER_ENABLE = 0, // Width of wuser signal parameter WUSER_WIDTH = 1, // Propagate buser signal parameter BUSER_ENABLE = 0, // Width of buser signal parameter BUSER_WIDTH = 1, // Propagate aruser signal parameter ARUSER_ENABLE = 0, // Width of aruser signal parameter ARUSER_WIDTH = 1, // Propagate ruser signal parameter RUSER_ENABLE = 0, // Width of ruser signal parameter RUSER_WIDTH = 1, // Number of concurrent unique IDs for each slave interface // S_COUNT concatenated fields of 32 bits parameter S_THREADS = {S_COUNT{32'd2}}, // Number of concurrent operations for each slave interface // S_COUNT concatenated fields of 32 bits parameter S_ACCEPT = {S_COUNT{32'd16}}, // Number of regions per master interface parameter M_REGIONS = 1, // Master interface base addresses // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits // set to zero for default addressing based on M_ADDR_WIDTH parameter M_BASE_ADDR = 0, // Master interface address widths // M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}}, // Read connections between interfaces // M_COUNT concatenated fields of S_COUNT bits parameter M_CONNECT_READ = {M_COUNT{{S_COUNT{1'b1}}}}, // Write connections between interfaces // M_COUNT concatenated fields of S_COUNT bits parameter M_CONNECT_WRITE = {M_COUNT{{S_COUNT{1'b1}}}}, // Number of concurrent operations for each master interface // M_COUNT concatenated fields of 32 bits parameter M_ISSUE = {M_COUNT{32'd4}}, // Secure master (fail operations based on awprot/arprot) // M_COUNT bits parameter M_SECURE = {M_COUNT{1'b0}}, // Slave interface AW channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_AW_REG_TYPE = {S_COUNT{2'd0}}, // Slave interface W channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_W_REG_TYPE = {S_COUNT{2'd0}}, // Slave interface B channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_B_REG_TYPE = {S_COUNT{2'd1}}, // Slave interface AR channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_AR_REG_TYPE = {S_COUNT{2'd0}}, // Slave interface R channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_R_REG_TYPE = {S_COUNT{2'd2}}, // Master interface AW channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_AW_REG_TYPE = {M_COUNT{2'd1}}, // Master interface W channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_W_REG_TYPE = {M_COUNT{2'd2}}, // Master interface B channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_B_REG_TYPE = {M_COUNT{2'd0}}, // Master interface AR channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_AR_REG_TYPE = {M_COUNT{2'd1}}, // Master interface R channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_R_REG_TYPE = {M_COUNT{2'd0}} ) ( input wire clk, input wire rst, /* * AXI slave interfaces */ input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_awid, input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_awaddr, input wire [S_COUNT*8-1:0] s_axi_awlen, input wire [S_COUNT*3-1:0] s_axi_awsize, input wire [S_COUNT*2-1:0] s_axi_awburst, input wire [S_COUNT-1:0] s_axi_awlock, input wire [S_COUNT*4-1:0] s_axi_awcache, input wire [S_COUNT*3-1:0] s_axi_awprot, input wire [S_COUNT*4-1:0] s_axi_awqos, input wire [S_COUNT*AWUSER_WIDTH-1:0] s_axi_awuser, input wire [S_COUNT-1:0] s_axi_awvalid, output wire [S_COUNT-1:0] s_axi_awready, input wire [S_COUNT*DATA_WIDTH-1:0] s_axi_wdata, input wire [S_COUNT*STRB_WIDTH-1:0] s_axi_wstrb, input wire [S_COUNT-1:0] s_axi_wlast, input wire [S_COUNT*WUSER_WIDTH-1:0] s_axi_wuser, input wire [S_COUNT-1:0] s_axi_wvalid, output wire [S_COUNT-1:0] s_axi_wready, output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_bid, output wire [S_COUNT*2-1:0] s_axi_bresp, output wire [S_COUNT*BUSER_WIDTH-1:0] s_axi_buser, output wire [S_COUNT-1:0] s_axi_bvalid, input wire [S_COUNT-1:0] s_axi_bready, input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_arid, input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_araddr, input wire [S_COUNT*8-1:0] s_axi_arlen, input wire [S_COUNT*3-1:0] s_axi_arsize, input wire [S_COUNT*2-1:0] s_axi_arburst, input wire [S_COUNT-1:0] s_axi_arlock, input wire [S_COUNT*4-1:0] s_axi_arcache, input wire [S_COUNT*3-1:0] s_axi_arprot, input wire [S_COUNT*4-1:0] s_axi_arqos, input wire [S_COUNT*ARUSER_WIDTH-1:0] s_axi_aruser, input wire [S_COUNT-1:0] s_axi_arvalid, output wire [S_COUNT-1:0] s_axi_arready, output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_rid, output wire [S_COUNT*DATA_WIDTH-1:0] s_axi_rdata, output wire [S_COUNT*2-1:0] s_axi_rresp, output wire [S_COUNT-1:0] s_axi_rlast, output wire [S_COUNT*RUSER_WIDTH-1:0] s_axi_ruser, output wire [S_COUNT-1:0] s_axi_rvalid, input wire [S_COUNT-1:0] s_axi_rready, /* * AXI master interfaces */ output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_awid, output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_awaddr, output wire [M_COUNT*8-1:0] m_axi_awlen, output wire [M_COUNT*3-1:0] m_axi_awsize, output wire [M_COUNT*2-1:0] m_axi_awburst, output wire [M_COUNT-1:0] m_axi_awlock, output wire [M_COUNT*4-1:0] m_axi_awcache, output wire [M_COUNT*3-1:0] m_axi_awprot, output wire [M_COUNT*4-1:0] m_axi_awqos, output wire [M_COUNT*4-1:0] m_axi_awregion, output wire [M_COUNT*AWUSER_WIDTH-1:0] m_axi_awuser, output wire [M_COUNT-1:0] m_axi_awvalid, input wire [M_COUNT-1:0] m_axi_awready, output wire [M_COUNT*DATA_WIDTH-1:0] m_axi_wdata, output wire [M_COUNT*STRB_WIDTH-1:0] m_axi_wstrb, output wire [M_COUNT-1:0] m_axi_wlast, output wire [M_COUNT*WUSER_WIDTH-1:0] m_axi_wuser, output wire [M_COUNT-1:0] m_axi_wvalid, input wire [M_COUNT-1:0] m_axi_wready, input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_bid, input wire [M_COUNT*2-1:0] m_axi_bresp, input wire [M_COUNT*BUSER_WIDTH-1:0] m_axi_buser, input wire [M_COUNT-1:0] m_axi_bvalid, output wire [M_COUNT-1:0] m_axi_bready, output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_arid, output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_araddr, output wire [M_COUNT*8-1:0] m_axi_arlen, output wire [M_COUNT*3-1:0] m_axi_arsize, output wire [M_COUNT*2-1:0] m_axi_arburst, output wire [M_COUNT-1:0] m_axi_arlock, output wire [M_COUNT*4-1:0] m_axi_arcache, output wire [M_COUNT*3-1:0] m_axi_arprot, output wire [M_COUNT*4-1:0] m_axi_arqos, output wire [M_COUNT*4-1:0] m_axi_arregion, output wire [M_COUNT*ARUSER_WIDTH-1:0] m_axi_aruser, output wire [M_COUNT-1:0] m_axi_arvalid, input wire [M_COUNT-1:0] m_axi_arready, input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_rid, input wire [M_COUNT*DATA_WIDTH-1:0] m_axi_rdata, input wire [M_COUNT*2-1:0] m_axi_rresp, input wire [M_COUNT-1:0] m_axi_rlast, input wire [M_COUNT*RUSER_WIDTH-1:0] m_axi_ruser, input wire [M_COUNT-1:0] m_axi_rvalid, output wire [M_COUNT-1:0] m_axi_rready ); axi_crossbar_wr #( .S_COUNT(S_COUNT), .M_COUNT(M_COUNT), .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .STRB_WIDTH(STRB_WIDTH), .S_ID_WIDTH(S_ID_WIDTH), .M_ID_WIDTH(M_ID_WIDTH), .AWUSER_ENABLE(AWUSER_ENABLE), .AWUSER_WIDTH(AWUSER_WIDTH), .WUSER_ENABLE(WUSER_ENABLE), .WUSER_WIDTH(WUSER_WIDTH), .BUSER_ENABLE(BUSER_ENABLE), .BUSER_WIDTH(BUSER_WIDTH), .S_THREADS(S_THREADS), .S_ACCEPT(S_ACCEPT), .M_REGIONS(M_REGIONS), .M_BASE_ADDR(M_BASE_ADDR), .M_ADDR_WIDTH(M_ADDR_WIDTH), .M_CONNECT(M_CONNECT_WRITE), .M_ISSUE(M_ISSUE), .M_SECURE(M_SECURE), .S_AW_REG_TYPE(S_AW_REG_TYPE), .S_W_REG_TYPE (S_W_REG_TYPE), .S_B_REG_TYPE (S_B_REG_TYPE) ) axi_crossbar_wr_inst ( .clk(clk), .rst(rst), /* * AXI slave interfaces */ .s_axi_awid(s_axi_awid), .s_axi_awaddr(s_axi_awaddr), .s_axi_awlen(s_axi_awlen), .s_axi_awsize(s_axi_awsize), .s_axi_awburst(s_axi_awburst), .s_axi_awlock(s_axi_awlock), .s_axi_awcache(s_axi_awcache), .s_axi_awprot(s_axi_awprot), .s_axi_awqos(s_axi_awqos), .s_axi_awuser(s_axi_awuser), .s_axi_awvalid(s_axi_awvalid), .s_axi_awready(s_axi_awready), .s_axi_wdata(s_axi_wdata), .s_axi_wstrb(s_axi_wstrb), .s_axi_wlast(s_axi_wlast), .s_axi_wuser(s_axi_wuser), .s_axi_wvalid(s_axi_wvalid), .s_axi_wready(s_axi_wready), .s_axi_bid(s_axi_bid), .s_axi_bresp(s_axi_bresp), .s_axi_buser(s_axi_buser), .s_axi_bvalid(s_axi_bvalid), .s_axi_bready(s_axi_bready), /* * AXI master interfaces */ .m_axi_awid(m_axi_awid), .m_axi_awaddr(m_axi_awaddr), .m_axi_awlen(m_axi_awlen), .m_axi_awsize(m_axi_awsize), .m_axi_awburst(m_axi_awburst), .m_axi_awlock(m_axi_awlock), .m_axi_awcache(m_axi_awcache), .m_axi_awprot(m_axi_awprot), .m_axi_awqos(m_axi_awqos), .m_axi_awregion(m_axi_awregion), .m_axi_awuser(m_axi_awuser), .m_axi_awvalid(m_axi_awvalid), .m_axi_awready(m_axi_awready), .m_axi_wdata(m_axi_wdata), .m_axi_wstrb(m_axi_wstrb), .m_axi_wlast(m_axi_wlast), .m_axi_wuser(m_axi_wuser), .m_axi_wvalid(m_axi_wvalid), .m_axi_wready(m_axi_wready), .m_axi_bid(m_axi_bid), .m_axi_bresp(m_axi_bresp), .m_axi_buser(m_axi_buser), .m_axi_bvalid(m_axi_bvalid), .m_axi_bready(m_axi_bready) ); axi_crossbar_rd #( .S_COUNT(S_COUNT), .M_COUNT(M_COUNT), .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .STRB_WIDTH(STRB_WIDTH), .S_ID_WIDTH(S_ID_WIDTH), .M_ID_WIDTH(M_ID_WIDTH), .ARUSER_ENABLE(ARUSER_ENABLE), .ARUSER_WIDTH(ARUSER_WIDTH), .RUSER_ENABLE(RUSER_ENABLE), .RUSER_WIDTH(RUSER_WIDTH), .S_THREADS(S_THREADS), .S_ACCEPT(S_ACCEPT), .M_REGIONS(M_REGIONS), .M_BASE_ADDR(M_BASE_ADDR), .M_ADDR_WIDTH(M_ADDR_WIDTH), .M_CONNECT(M_CONNECT_READ), .M_ISSUE(M_ISSUE), .M_SECURE(M_SECURE), .S_AR_REG_TYPE(S_AR_REG_TYPE), .S_R_REG_TYPE (S_R_REG_TYPE) ) axi_crossbar_rd_inst ( .clk(clk), .rst(rst), /* * AXI slave interfaces */ .s_axi_arid(s_axi_arid), .s_axi_araddr(s_axi_araddr), .s_axi_arlen(s_axi_arlen), .s_axi_arsize(s_axi_arsize), .s_axi_arburst(s_axi_arburst), .s_axi_arlock(s_axi_arlock), .s_axi_arcache(s_axi_arcache), .s_axi_arprot(s_axi_arprot), .s_axi_arqos(s_axi_arqos), .s_axi_aruser(s_axi_aruser), .s_axi_arvalid(s_axi_arvalid), .s_axi_arready(s_axi_arready), .s_axi_rid(s_axi_rid), .s_axi_rdata(s_axi_rdata), .s_axi_rresp(s_axi_rresp), .s_axi_rlast(s_axi_rlast), .s_axi_ruser(s_axi_ruser), .s_axi_rvalid(s_axi_rvalid), .s_axi_rready(s_axi_rready), /* * AXI master interfaces */ .m_axi_arid(m_axi_arid), .m_axi_araddr(m_axi_araddr), .m_axi_arlen(m_axi_arlen), .m_axi_arsize(m_axi_arsize), .m_axi_arburst(m_axi_arburst), .m_axi_arlock(m_axi_arlock), .m_axi_arcache(m_axi_arcache), .m_axi_arprot(m_axi_arprot), .m_axi_arqos(m_axi_arqos), .m_axi_arregion(m_axi_arregion), .m_axi_aruser(m_axi_aruser), .m_axi_arvalid(m_axi_arvalid), .m_axi_arready(m_axi_arready), .m_axi_rid(m_axi_rid), .m_axi_rdata(m_axi_rdata), .m_axi_rresp(m_axi_rresp), .m_axi_rlast(m_axi_rlast), .m_axi_ruser(m_axi_ruser), .m_axi_rvalid(m_axi_rvalid), .m_axi_rready(m_axi_rready) ); endmodule `resetall ================================================ FILE: testbench/axi4_mux/axi_crossbar_addr.v ================================================ /* Copyright (c) 2018 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * AXI4 crossbar address decode and admission control */ module axi_crossbar_addr # ( // Slave interface index parameter S = 0, // Number of AXI inputs (slave interfaces) parameter S_COUNT = 4, // Number of AXI outputs (master interfaces) parameter M_COUNT = 4, // Width of address bus in bits parameter ADDR_WIDTH = 32, // ID field width parameter ID_WIDTH = 8, // Number of concurrent unique IDs parameter S_THREADS = 32'd2, // Number of concurrent operations parameter S_ACCEPT = 32'd16, // Number of regions per master interface parameter M_REGIONS = 1, // Master interface base addresses // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits // set to zero for default addressing based on M_ADDR_WIDTH parameter M_BASE_ADDR = 0, // Master interface address widths // M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}}, // Connections between interfaces // M_COUNT concatenated fields of S_COUNT bits parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}}, // Secure master (fail operations based on awprot/arprot) // M_COUNT bits parameter M_SECURE = {M_COUNT{1'b0}}, // Enable write command output parameter WC_OUTPUT = 0 ) ( input wire clk, input wire rst, /* * Address input */ input wire [ID_WIDTH-1:0] s_axi_aid, input wire [ADDR_WIDTH-1:0] s_axi_aaddr, input wire [2:0] s_axi_aprot, input wire [3:0] s_axi_aqos, input wire s_axi_avalid, output wire s_axi_aready, /* * Address output */ output wire [3:0] m_axi_aregion, output wire [$clog2(M_COUNT)-1:0] m_select, output wire m_axi_avalid, input wire m_axi_aready, /* * Write command output */ output wire [$clog2(M_COUNT)-1:0] m_wc_select, output wire m_wc_decerr, output wire m_wc_valid, input wire m_wc_ready, /* * Reply command output */ output wire m_rc_decerr, output wire m_rc_valid, input wire m_rc_ready, /* * Completion input */ input wire [ID_WIDTH-1:0] s_cpl_id, input wire s_cpl_valid ); parameter CL_S_COUNT = $clog2(S_COUNT); parameter CL_M_COUNT = $clog2(M_COUNT); parameter S_INT_THREADS = S_THREADS > S_ACCEPT ? S_ACCEPT : S_THREADS; parameter CL_S_INT_THREADS = $clog2(S_INT_THREADS); parameter CL_S_ACCEPT = $clog2(S_ACCEPT); // default address computation function [M_COUNT*M_REGIONS*ADDR_WIDTH-1:0] calcBaseAddrs(input [31:0] dummy); integer i; reg [ADDR_WIDTH-1:0] base; reg [ADDR_WIDTH-1:0] width; reg [ADDR_WIDTH-1:0] size; reg [ADDR_WIDTH-1:0] mask; begin calcBaseAddrs = {M_COUNT*M_REGIONS*ADDR_WIDTH{1'b0}}; base = 0; for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin width = M_ADDR_WIDTH[i*32 +: 32]; mask = {ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - width); size = mask + 1; if (width > 0) begin if ((base & mask) != 0) begin base = base + size - (base & mask); // align end calcBaseAddrs[i * ADDR_WIDTH +: ADDR_WIDTH] = base; base = base + size; // increment end end end endfunction parameter M_BASE_ADDR_INT = M_BASE_ADDR ? M_BASE_ADDR : calcBaseAddrs(0); integer i, j; // check configuration initial begin if (S_ACCEPT < 1) begin $error("Error: need at least 1 accept (instance %m)"); $finish; end if (S_THREADS < 1) begin $error("Error: need at least 1 thread (instance %m)"); $finish; end if (S_THREADS > S_ACCEPT) begin $warning("Warning: requested thread count larger than accept count; limiting thread count to accept count (instance %m)"); end if (M_REGIONS < 1) begin $error("Error: need at least 1 region (instance %m)"); $finish; end for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin $error("Error: address width out of range (instance %m)"); $finish; end end $display("Addressing configuration for axi_crossbar_addr instance %m"); for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin if (M_ADDR_WIDTH[i*32 +: 32]) begin $display("%2d (%2d): %x / %02d -- %x-%x", i/M_REGIONS, i%M_REGIONS, M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[i*32 +: 32], M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])) ); end end for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin if ((M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & (2**M_ADDR_WIDTH[i*32 +: 32]-1)) != 0) begin $display("Region not aligned:"); $display("%2d (%2d): %x / %2d -- %x-%x", i/M_REGIONS, i%M_REGIONS, M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[i*32 +: 32], M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])) ); $error("Error: address range not aligned (instance %m)"); $finish; end end for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin for (j = i+1; j < M_COUNT*M_REGIONS; j = j + 1) begin if (M_ADDR_WIDTH[i*32 +: 32] && M_ADDR_WIDTH[j*32 +: 32]) begin if (((M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32])) <= (M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])))) && ((M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32])) <= (M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32]))))) begin $display("Overlapping regions:"); $display("%2d (%2d): %x / %2d -- %x-%x", i/M_REGIONS, i%M_REGIONS, M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[i*32 +: 32], M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])) ); $display("%2d (%2d): %x / %2d -- %x-%x", j/M_REGIONS, j%M_REGIONS, M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[j*32 +: 32], M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32]), M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])) ); $error("Error: address ranges overlap (instance %m)"); $finish; end end end end end localparam [2:0] STATE_IDLE = 3'd0, STATE_DECODE = 3'd1; reg [2:0] state_reg = STATE_IDLE, state_next; reg s_axi_aready_reg = 0, s_axi_aready_next; reg [3:0] m_axi_aregion_reg = 4'd0, m_axi_aregion_next; reg [CL_M_COUNT-1:0] m_select_reg = 0, m_select_next; reg m_axi_avalid_reg = 1'b0, m_axi_avalid_next; reg m_decerr_reg = 1'b0, m_decerr_next; reg m_wc_valid_reg = 1'b0, m_wc_valid_next; reg m_rc_valid_reg = 1'b0, m_rc_valid_next; assign s_axi_aready = s_axi_aready_reg; assign m_axi_aregion = m_axi_aregion_reg; assign m_select = m_select_reg; assign m_axi_avalid = m_axi_avalid_reg; assign m_wc_select = m_select_reg; assign m_wc_decerr = m_decerr_reg; assign m_wc_valid = m_wc_valid_reg; assign m_rc_decerr = m_decerr_reg; assign m_rc_valid = m_rc_valid_reg; reg match; reg trans_start; reg trans_complete; reg [$clog2(S_ACCEPT+1)-1:0] trans_count_reg = 0; wire trans_limit = trans_count_reg >= S_ACCEPT && !trans_complete; // transfer ID thread tracking reg [ID_WIDTH-1:0] thread_id_reg[S_INT_THREADS-1:0]; reg [CL_M_COUNT-1:0] thread_m_reg[S_INT_THREADS-1:0]; reg [3:0] thread_region_reg[S_INT_THREADS-1:0]; reg [$clog2(S_ACCEPT+1)-1:0] thread_count_reg[S_INT_THREADS-1:0]; wire [S_INT_THREADS-1:0] thread_active; wire [S_INT_THREADS-1:0] thread_match; wire [S_INT_THREADS-1:0] thread_match_dest; wire [S_INT_THREADS-1:0] thread_cpl_match; wire [S_INT_THREADS-1:0] thread_trans_start; wire [S_INT_THREADS-1:0] thread_trans_complete; generate genvar n; for (n = 0; n < S_INT_THREADS; n = n + 1) begin initial begin thread_count_reg[n] <= 0; end assign thread_active[n] = thread_count_reg[n] != 0; assign thread_match[n] = thread_active[n] && thread_id_reg[n] == s_axi_aid; assign thread_match_dest[n] = thread_match[n] && thread_m_reg[n] == m_select_next && (M_REGIONS < 2 || thread_region_reg[n] == m_axi_aregion_next); assign thread_cpl_match[n] = thread_active[n] && thread_id_reg[n] == s_cpl_id; assign thread_trans_start[n] = (thread_match[n] || (!thread_active[n] && !thread_match && !(thread_trans_start & ({S_INT_THREADS{1'b1}} >> (S_INT_THREADS-n))))) && trans_start; assign thread_trans_complete[n] = thread_cpl_match[n] && trans_complete; always @(posedge clk) begin if (rst) begin thread_count_reg[n] <= 0; end else begin if (thread_trans_start[n] && !thread_trans_complete[n]) begin thread_count_reg[n] <= thread_count_reg[n] + 1; end else if (!thread_trans_start[n] && thread_trans_complete[n]) begin thread_count_reg[n] <= thread_count_reg[n] - 1; end end if (thread_trans_start[n]) begin thread_id_reg[n] <= s_axi_aid; thread_m_reg[n] <= m_select_next; thread_region_reg[n] <= m_axi_aregion_next; end end end endgenerate always @* begin state_next = STATE_IDLE; match = 1'b0; trans_start = 1'b0; trans_complete = 1'b0; s_axi_aready_next = 1'b0; m_axi_aregion_next = m_axi_aregion_reg; m_select_next = m_select_reg; m_axi_avalid_next = m_axi_avalid_reg && !m_axi_aready; m_decerr_next = m_decerr_reg; m_wc_valid_next = m_wc_valid_reg && !m_wc_ready; m_rc_valid_next = m_rc_valid_reg && !m_rc_ready; case (state_reg) STATE_IDLE: begin // idle state, store values s_axi_aready_next = 1'b0; if (s_axi_avalid && !s_axi_aready) begin match = 1'b0; for (i = 0; i < M_COUNT; i = i + 1) begin for (j = 0; j < M_REGIONS; j = j + 1) begin if (M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32] && (!M_SECURE[i] || !s_axi_aprot[1]) && (M_CONNECT & (1 << (S+i*S_COUNT))) && (s_axi_aaddr >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32]) == (M_BASE_ADDR_INT[(i*M_REGIONS+j)*ADDR_WIDTH +: ADDR_WIDTH] >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32])) begin m_select_next = i; m_axi_aregion_next = j; match = 1'b1; end end end if (match) begin // address decode successful if (!trans_limit && (thread_match_dest || (!(&thread_active) && !thread_match))) begin // transaction limit not reached m_axi_avalid_next = 1'b1; m_decerr_next = 1'b0; m_wc_valid_next = WC_OUTPUT; m_rc_valid_next = 1'b0; trans_start = 1'b1; state_next = STATE_DECODE; end else begin // transaction limit reached; block in idle state_next = STATE_IDLE; end end else begin // decode error m_axi_avalid_next = 1'b0; m_decerr_next = 1'b1; m_wc_valid_next = WC_OUTPUT; m_rc_valid_next = 1'b1; state_next = STATE_DECODE; end end else begin state_next = STATE_IDLE; end end STATE_DECODE: begin if (!m_axi_avalid_next && (!m_wc_valid_next || !WC_OUTPUT) && !m_rc_valid_next) begin s_axi_aready_next = 1'b1; state_next = STATE_IDLE; end else begin state_next = STATE_DECODE; end end endcase // manage completions trans_complete = s_cpl_valid; end always @(posedge clk) begin if (rst) begin state_reg <= STATE_IDLE; s_axi_aready_reg <= 1'b0; m_axi_avalid_reg <= 1'b0; m_wc_valid_reg <= 1'b0; m_rc_valid_reg <= 1'b0; trans_count_reg <= 0; end else begin state_reg <= state_next; s_axi_aready_reg <= s_axi_aready_next; m_axi_avalid_reg <= m_axi_avalid_next; m_wc_valid_reg <= m_wc_valid_next; m_rc_valid_reg <= m_rc_valid_next; if (trans_start && !trans_complete) begin trans_count_reg <= trans_count_reg + 1; end else if (!trans_start && trans_complete) begin trans_count_reg <= trans_count_reg - 1; end end m_axi_aregion_reg <= m_axi_aregion_next; m_select_reg <= m_select_next; m_decerr_reg <= m_decerr_next; end endmodule `resetall ================================================ FILE: testbench/axi4_mux/axi_crossbar_rd.v ================================================ /* Copyright (c) 2018 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * AXI4 crossbar (read) */ module axi_crossbar_rd # ( // Number of AXI inputs (slave interfaces) parameter S_COUNT = 4, // Number of AXI outputs (master interfaces) parameter M_COUNT = 4, // Width of data bus in bits parameter DATA_WIDTH = 32, // Width of address bus in bits parameter ADDR_WIDTH = 32, // Width of wstrb (width of data bus in words) parameter STRB_WIDTH = (DATA_WIDTH/8), // Input ID field width (from AXI masters) parameter S_ID_WIDTH = 8, // Output ID field width (towards AXI slaves) // Additional bits required for response routing parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT), // Propagate aruser signal parameter ARUSER_ENABLE = 0, // Width of aruser signal parameter ARUSER_WIDTH = 1, // Propagate ruser signal parameter RUSER_ENABLE = 0, // Width of ruser signal parameter RUSER_WIDTH = 1, // Number of concurrent unique IDs for each slave interface // S_COUNT concatenated fields of 32 bits parameter S_THREADS = {S_COUNT{32'd2}}, // Number of concurrent operations for each slave interface // S_COUNT concatenated fields of 32 bits parameter S_ACCEPT = {S_COUNT{32'd16}}, // Number of regions per master interface parameter M_REGIONS = 1, // Master interface base addresses // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits // set to zero for default addressing based on M_ADDR_WIDTH parameter M_BASE_ADDR = 0, // Master interface address widths // M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}}, // Read connections between interfaces // M_COUNT concatenated fields of S_COUNT bits parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}}, // Number of concurrent operations for each master interface // M_COUNT concatenated fields of 32 bits parameter M_ISSUE = {M_COUNT{32'd4}}, // Secure master (fail operations based on awprot/arprot) // M_COUNT bits parameter M_SECURE = {M_COUNT{1'b0}}, // Slave interface AR channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_AR_REG_TYPE = {S_COUNT{2'd0}}, // Slave interface R channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_R_REG_TYPE = {S_COUNT{2'd2}}, // Master interface AR channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_AR_REG_TYPE = {M_COUNT{2'd1}}, // Master interface R channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_R_REG_TYPE = {M_COUNT{2'd0}} ) ( input wire clk, input wire rst, /* * AXI slave interfaces */ input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_arid, input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_araddr, input wire [S_COUNT*8-1:0] s_axi_arlen, input wire [S_COUNT*3-1:0] s_axi_arsize, input wire [S_COUNT*2-1:0] s_axi_arburst, input wire [S_COUNT-1:0] s_axi_arlock, input wire [S_COUNT*4-1:0] s_axi_arcache, input wire [S_COUNT*3-1:0] s_axi_arprot, input wire [S_COUNT*4-1:0] s_axi_arqos, input wire [S_COUNT*ARUSER_WIDTH-1:0] s_axi_aruser, input wire [S_COUNT-1:0] s_axi_arvalid, output wire [S_COUNT-1:0] s_axi_arready, output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_rid, output wire [S_COUNT*DATA_WIDTH-1:0] s_axi_rdata, output wire [S_COUNT*2-1:0] s_axi_rresp, output wire [S_COUNT-1:0] s_axi_rlast, output wire [S_COUNT*RUSER_WIDTH-1:0] s_axi_ruser, output wire [S_COUNT-1:0] s_axi_rvalid, input wire [S_COUNT-1:0] s_axi_rready, /* * AXI master interfaces */ output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_arid, output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_araddr, output wire [M_COUNT*8-1:0] m_axi_arlen, output wire [M_COUNT*3-1:0] m_axi_arsize, output wire [M_COUNT*2-1:0] m_axi_arburst, output wire [M_COUNT-1:0] m_axi_arlock, output wire [M_COUNT*4-1:0] m_axi_arcache, output wire [M_COUNT*3-1:0] m_axi_arprot, output wire [M_COUNT*4-1:0] m_axi_arqos, output wire [M_COUNT*4-1:0] m_axi_arregion, output wire [M_COUNT*ARUSER_WIDTH-1:0] m_axi_aruser, output wire [M_COUNT-1:0] m_axi_arvalid, input wire [M_COUNT-1:0] m_axi_arready, input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_rid, input wire [M_COUNT*DATA_WIDTH-1:0] m_axi_rdata, input wire [M_COUNT*2-1:0] m_axi_rresp, input wire [M_COUNT-1:0] m_axi_rlast, input wire [M_COUNT*RUSER_WIDTH-1:0] m_axi_ruser, input wire [M_COUNT-1:0] m_axi_rvalid, output wire [M_COUNT-1:0] m_axi_rready ); parameter CL_S_COUNT = $clog2(S_COUNT); parameter CL_M_COUNT = $clog2(M_COUNT); parameter M_COUNT_P1 = M_COUNT+1; parameter CL_M_COUNT_P1 = $clog2(M_COUNT_P1); integer i; // check configuration initial begin if (M_ID_WIDTH < S_ID_WIDTH+$clog2(S_COUNT)) begin $error("Error: M_ID_WIDTH must be at least $clog2(S_COUNT) larger than S_ID_WIDTH (instance %m)"); $finish; end for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin $error("Error: value out of range (instance %m)"); $finish; end end end wire [S_COUNT*S_ID_WIDTH-1:0] int_s_axi_arid; wire [S_COUNT*ADDR_WIDTH-1:0] int_s_axi_araddr; wire [S_COUNT*8-1:0] int_s_axi_arlen; wire [S_COUNT*3-1:0] int_s_axi_arsize; wire [S_COUNT*2-1:0] int_s_axi_arburst; wire [S_COUNT-1:0] int_s_axi_arlock; wire [S_COUNT*4-1:0] int_s_axi_arcache; wire [S_COUNT*3-1:0] int_s_axi_arprot; wire [S_COUNT*4-1:0] int_s_axi_arqos; wire [S_COUNT*4-1:0] int_s_axi_arregion; wire [S_COUNT*ARUSER_WIDTH-1:0] int_s_axi_aruser; wire [S_COUNT-1:0] int_s_axi_arvalid; wire [S_COUNT-1:0] int_s_axi_arready; wire [S_COUNT*M_COUNT-1:0] int_axi_arvalid; wire [M_COUNT*S_COUNT-1:0] int_axi_arready; wire [M_COUNT*M_ID_WIDTH-1:0] int_m_axi_rid; wire [M_COUNT*DATA_WIDTH-1:0] int_m_axi_rdata; wire [M_COUNT*2-1:0] int_m_axi_rresp; wire [M_COUNT-1:0] int_m_axi_rlast; wire [M_COUNT*RUSER_WIDTH-1:0] int_m_axi_ruser; wire [M_COUNT-1:0] int_m_axi_rvalid; wire [M_COUNT-1:0] int_m_axi_rready; wire [M_COUNT*S_COUNT-1:0] int_axi_rvalid; wire [S_COUNT*M_COUNT-1:0] int_axi_rready; generate genvar m, n; for (m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces // address decode and admission control wire [CL_M_COUNT-1:0] a_select; wire m_axi_avalid; wire m_axi_aready; wire m_rc_decerr; wire m_rc_valid; wire m_rc_ready; wire [S_ID_WIDTH-1:0] s_cpl_id; wire s_cpl_valid; axi_crossbar_addr #( .S(m), .S_COUNT(S_COUNT), .M_COUNT(M_COUNT), .ADDR_WIDTH(ADDR_WIDTH), .ID_WIDTH(S_ID_WIDTH), .S_THREADS(S_THREADS[m*32 +: 32]), .S_ACCEPT(S_ACCEPT[m*32 +: 32]), .M_REGIONS(M_REGIONS), .M_BASE_ADDR(M_BASE_ADDR), .M_ADDR_WIDTH(M_ADDR_WIDTH), .M_CONNECT(M_CONNECT), .M_SECURE(M_SECURE), .WC_OUTPUT(0) ) addr_inst ( .clk(clk), .rst(rst), /* * Address input */ .s_axi_aid(int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]), .s_axi_aaddr(int_s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]), .s_axi_aprot(int_s_axi_arprot[m*3 +: 3]), .s_axi_aqos(int_s_axi_arqos[m*4 +: 4]), .s_axi_avalid(int_s_axi_arvalid[m]), .s_axi_aready(int_s_axi_arready[m]), /* * Address output */ .m_axi_aregion(int_s_axi_arregion[m*4 +: 4]), .m_select(a_select), .m_axi_avalid(m_axi_avalid), .m_axi_aready(m_axi_aready), /* * Write command output */ .m_wc_select(), .m_wc_decerr(), .m_wc_valid(), .m_wc_ready(1'b1), /* * Response command output */ .m_rc_decerr(m_rc_decerr), .m_rc_valid(m_rc_valid), .m_rc_ready(m_rc_ready), /* * Completion input */ .s_cpl_id(s_cpl_id), .s_cpl_valid(s_cpl_valid) ); assign int_axi_arvalid[m*M_COUNT +: M_COUNT] = m_axi_avalid << a_select; assign m_axi_aready = int_axi_arready[a_select*S_COUNT+m]; // decode error handling reg [S_ID_WIDTH-1:0] decerr_m_axi_rid_reg = {S_ID_WIDTH{1'b0}}, decerr_m_axi_rid_next; reg decerr_m_axi_rlast_reg = 1'b0, decerr_m_axi_rlast_next; reg decerr_m_axi_rvalid_reg = 1'b0, decerr_m_axi_rvalid_next; wire decerr_m_axi_rready; reg [7:0] decerr_len_reg = 8'd0, decerr_len_next; assign m_rc_ready = !decerr_m_axi_rvalid_reg; always @* begin decerr_len_next = decerr_len_reg; decerr_m_axi_rid_next = decerr_m_axi_rid_reg; decerr_m_axi_rlast_next = decerr_m_axi_rlast_reg; decerr_m_axi_rvalid_next = decerr_m_axi_rvalid_reg; if (decerr_m_axi_rvalid_reg) begin if (decerr_m_axi_rready) begin if (decerr_len_reg > 0) begin decerr_len_next = decerr_len_reg-1; decerr_m_axi_rlast_next = (decerr_len_next == 0); decerr_m_axi_rvalid_next = 1'b1; end else begin decerr_m_axi_rvalid_next = 1'b0; end end end else if (m_rc_valid && m_rc_ready) begin decerr_len_next = int_s_axi_arlen[m*8 +: 8]; decerr_m_axi_rid_next = int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]; decerr_m_axi_rlast_next = (decerr_len_next == 0); decerr_m_axi_rvalid_next = 1'b1; end end always @(posedge clk) begin if (rst) begin decerr_m_axi_rvalid_reg <= 1'b0; end else begin decerr_m_axi_rvalid_reg <= decerr_m_axi_rvalid_next; end decerr_m_axi_rid_reg <= decerr_m_axi_rid_next; decerr_m_axi_rlast_reg <= decerr_m_axi_rlast_next; decerr_len_reg <= decerr_len_next; end // read response arbitration wire [M_COUNT_P1-1:0] r_request; wire [M_COUNT_P1-1:0] r_acknowledge; wire [M_COUNT_P1-1:0] r_grant; wire r_grant_valid; wire [CL_M_COUNT_P1-1:0] r_grant_encoded; arbiter #( .PORTS(M_COUNT_P1), .ARB_TYPE_ROUND_ROBIN(1), .ARB_BLOCK(1), .ARB_BLOCK_ACK(1), .ARB_LSB_HIGH_PRIORITY(1) ) r_arb_inst ( .clk(clk), .rst(rst), .request(r_request), .acknowledge(r_acknowledge), .grant(r_grant), .grant_valid(r_grant_valid), .grant_encoded(r_grant_encoded) ); // read response mux wire [S_ID_WIDTH-1:0] m_axi_rid_mux = {decerr_m_axi_rid_reg, int_m_axi_rid} >> r_grant_encoded*M_ID_WIDTH; wire [DATA_WIDTH-1:0] m_axi_rdata_mux = {{DATA_WIDTH{1'b0}}, int_m_axi_rdata} >> r_grant_encoded*DATA_WIDTH; wire [1:0] m_axi_rresp_mux = {2'b11, int_m_axi_rresp} >> r_grant_encoded*2; wire m_axi_rlast_mux = {decerr_m_axi_rlast_reg, int_m_axi_rlast} >> r_grant_encoded; wire [RUSER_WIDTH-1:0] m_axi_ruser_mux = {{RUSER_WIDTH{1'b0}}, int_m_axi_ruser} >> r_grant_encoded*RUSER_WIDTH; wire m_axi_rvalid_mux = ({decerr_m_axi_rvalid_reg, int_m_axi_rvalid} >> r_grant_encoded) & r_grant_valid; wire m_axi_rready_mux; assign int_axi_rready[m*M_COUNT +: M_COUNT] = (r_grant_valid && m_axi_rready_mux) << r_grant_encoded; assign decerr_m_axi_rready = (r_grant_valid && m_axi_rready_mux) && (r_grant_encoded == M_COUNT_P1-1); for (n = 0; n < M_COUNT; n = n + 1) begin assign r_request[n] = int_axi_rvalid[n*S_COUNT+m] && !r_grant[n]; assign r_acknowledge[n] = r_grant[n] && int_axi_rvalid[n*S_COUNT+m] && m_axi_rlast_mux && m_axi_rready_mux; end assign r_request[M_COUNT_P1-1] = decerr_m_axi_rvalid_reg && !r_grant[M_COUNT_P1-1]; assign r_acknowledge[M_COUNT_P1-1] = r_grant[M_COUNT_P1-1] && decerr_m_axi_rvalid_reg && decerr_m_axi_rlast_reg && m_axi_rready_mux; assign s_cpl_id = m_axi_rid_mux; assign s_cpl_valid = m_axi_rvalid_mux && m_axi_rready_mux && m_axi_rlast_mux; // S side register axi_register_rd #( .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .STRB_WIDTH(STRB_WIDTH), .ID_WIDTH(S_ID_WIDTH), .ARUSER_ENABLE(ARUSER_ENABLE), .ARUSER_WIDTH(ARUSER_WIDTH), .RUSER_ENABLE(RUSER_ENABLE), .RUSER_WIDTH(RUSER_WIDTH), .AR_REG_TYPE(S_AR_REG_TYPE[m*2 +: 2]), .R_REG_TYPE(S_R_REG_TYPE[m*2 +: 2]) ) reg_inst ( .clk(clk), .rst(rst), .s_axi_arid(s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]), .s_axi_araddr(s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]), .s_axi_arlen(s_axi_arlen[m*8 +: 8]), .s_axi_arsize(s_axi_arsize[m*3 +: 3]), .s_axi_arburst(s_axi_arburst[m*2 +: 2]), .s_axi_arlock(s_axi_arlock[m]), .s_axi_arcache(s_axi_arcache[m*4 +: 4]), .s_axi_arprot(s_axi_arprot[m*3 +: 3]), .s_axi_arqos(s_axi_arqos[m*4 +: 4]), .s_axi_arregion(4'd0), .s_axi_aruser(s_axi_aruser[m*ARUSER_WIDTH +: ARUSER_WIDTH]), .s_axi_arvalid(s_axi_arvalid[m]), .s_axi_arready(s_axi_arready[m]), .s_axi_rid(s_axi_rid[m*S_ID_WIDTH +: S_ID_WIDTH]), .s_axi_rdata(s_axi_rdata[m*DATA_WIDTH +: DATA_WIDTH]), .s_axi_rresp(s_axi_rresp[m*2 +: 2]), .s_axi_rlast(s_axi_rlast[m]), .s_axi_ruser(s_axi_ruser[m*RUSER_WIDTH +: RUSER_WIDTH]), .s_axi_rvalid(s_axi_rvalid[m]), .s_axi_rready(s_axi_rready[m]), .m_axi_arid(int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]), .m_axi_araddr(int_s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]), .m_axi_arlen(int_s_axi_arlen[m*8 +: 8]), .m_axi_arsize(int_s_axi_arsize[m*3 +: 3]), .m_axi_arburst(int_s_axi_arburst[m*2 +: 2]), .m_axi_arlock(int_s_axi_arlock[m]), .m_axi_arcache(int_s_axi_arcache[m*4 +: 4]), .m_axi_arprot(int_s_axi_arprot[m*3 +: 3]), .m_axi_arqos(int_s_axi_arqos[m*4 +: 4]), .m_axi_arregion(), .m_axi_aruser(int_s_axi_aruser[m*ARUSER_WIDTH +: ARUSER_WIDTH]), .m_axi_arvalid(int_s_axi_arvalid[m]), .m_axi_arready(int_s_axi_arready[m]), .m_axi_rid(m_axi_rid_mux), .m_axi_rdata(m_axi_rdata_mux), .m_axi_rresp(m_axi_rresp_mux), .m_axi_rlast(m_axi_rlast_mux), .m_axi_ruser(m_axi_ruser_mux), .m_axi_rvalid(m_axi_rvalid_mux), .m_axi_rready(m_axi_rready_mux) ); end // s_ifaces for (n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces // in-flight transaction count wire trans_start; wire trans_complete; reg [$clog2(M_ISSUE[n*32 +: 32]+1)-1:0] trans_count_reg = 0; wire trans_limit = trans_count_reg >= M_ISSUE[n*32 +: 32] && !trans_complete; always @(posedge clk) begin if (rst) begin trans_count_reg <= 0; end else begin if (trans_start && !trans_complete) begin trans_count_reg <= trans_count_reg + 1; end else if (!trans_start && trans_complete) begin trans_count_reg <= trans_count_reg - 1; end end end // address arbitration wire [S_COUNT-1:0] a_request; wire [S_COUNT-1:0] a_acknowledge; wire [S_COUNT-1:0] a_grant; wire a_grant_valid; wire [CL_S_COUNT-1:0] a_grant_encoded; arbiter #( .PORTS(S_COUNT), .ARB_TYPE_ROUND_ROBIN(1), .ARB_BLOCK(1), .ARB_BLOCK_ACK(1), .ARB_LSB_HIGH_PRIORITY(1) ) a_arb_inst ( .clk(clk), .rst(rst), .request(a_request), .acknowledge(a_acknowledge), .grant(a_grant), .grant_valid(a_grant_valid), .grant_encoded(a_grant_encoded) ); // address mux wire [M_ID_WIDTH-1:0] s_axi_arid_mux = int_s_axi_arid[a_grant_encoded*S_ID_WIDTH +: S_ID_WIDTH] | (a_grant_encoded << S_ID_WIDTH); wire [ADDR_WIDTH-1:0] s_axi_araddr_mux = int_s_axi_araddr[a_grant_encoded*ADDR_WIDTH +: ADDR_WIDTH]; wire [7:0] s_axi_arlen_mux = int_s_axi_arlen[a_grant_encoded*8 +: 8]; wire [2:0] s_axi_arsize_mux = int_s_axi_arsize[a_grant_encoded*3 +: 3]; wire [1:0] s_axi_arburst_mux = int_s_axi_arburst[a_grant_encoded*2 +: 2]; wire s_axi_arlock_mux = int_s_axi_arlock[a_grant_encoded]; wire [3:0] s_axi_arcache_mux = int_s_axi_arcache[a_grant_encoded*4 +: 4]; wire [2:0] s_axi_arprot_mux = int_s_axi_arprot[a_grant_encoded*3 +: 3]; wire [3:0] s_axi_arqos_mux = int_s_axi_arqos[a_grant_encoded*4 +: 4]; wire [3:0] s_axi_arregion_mux = int_s_axi_arregion[a_grant_encoded*4 +: 4]; wire [ARUSER_WIDTH-1:0] s_axi_aruser_mux = int_s_axi_aruser[a_grant_encoded*ARUSER_WIDTH +: ARUSER_WIDTH]; wire s_axi_arvalid_mux = int_axi_arvalid[a_grant_encoded*M_COUNT+n] && a_grant_valid; wire s_axi_arready_mux; assign int_axi_arready[n*S_COUNT +: S_COUNT] = (a_grant_valid && s_axi_arready_mux) << a_grant_encoded; for (m = 0; m < S_COUNT; m = m + 1) begin assign a_request[m] = int_axi_arvalid[m*M_COUNT+n] && !a_grant[m] && !trans_limit; assign a_acknowledge[m] = a_grant[m] && int_axi_arvalid[m*M_COUNT+n] && s_axi_arready_mux; end assign trans_start = s_axi_arvalid_mux && s_axi_arready_mux && a_grant_valid; // read response forwarding wire [CL_S_COUNT-1:0] r_select = m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH] >> S_ID_WIDTH; assign int_axi_rvalid[n*S_COUNT +: S_COUNT] = int_m_axi_rvalid[n] << r_select; assign int_m_axi_rready[n] = int_axi_rready[r_select*M_COUNT+n]; assign trans_complete = int_m_axi_rvalid[n] && int_m_axi_rready[n] && int_m_axi_rlast[n]; // M side register axi_register_rd #( .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .STRB_WIDTH(STRB_WIDTH), .ID_WIDTH(M_ID_WIDTH), .ARUSER_ENABLE(ARUSER_ENABLE), .ARUSER_WIDTH(ARUSER_WIDTH), .RUSER_ENABLE(RUSER_ENABLE), .RUSER_WIDTH(RUSER_WIDTH), .AR_REG_TYPE(M_AR_REG_TYPE[n*2 +: 2]), .R_REG_TYPE(M_R_REG_TYPE[n*2 +: 2]) ) reg_inst ( .clk(clk), .rst(rst), .s_axi_arid(s_axi_arid_mux), .s_axi_araddr(s_axi_araddr_mux), .s_axi_arlen(s_axi_arlen_mux), .s_axi_arsize(s_axi_arsize_mux), .s_axi_arburst(s_axi_arburst_mux), .s_axi_arlock(s_axi_arlock_mux), .s_axi_arcache(s_axi_arcache_mux), .s_axi_arprot(s_axi_arprot_mux), .s_axi_arqos(s_axi_arqos_mux), .s_axi_arregion(s_axi_arregion_mux), .s_axi_aruser(s_axi_aruser_mux), .s_axi_arvalid(s_axi_arvalid_mux), .s_axi_arready(s_axi_arready_mux), .s_axi_rid(int_m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH]), .s_axi_rdata(int_m_axi_rdata[n*DATA_WIDTH +: DATA_WIDTH]), .s_axi_rresp(int_m_axi_rresp[n*2 +: 2]), .s_axi_rlast(int_m_axi_rlast[n]), .s_axi_ruser(int_m_axi_ruser[n*RUSER_WIDTH +: RUSER_WIDTH]), .s_axi_rvalid(int_m_axi_rvalid[n]), .s_axi_rready(int_m_axi_rready[n]), .m_axi_arid(m_axi_arid[n*M_ID_WIDTH +: M_ID_WIDTH]), .m_axi_araddr(m_axi_araddr[n*ADDR_WIDTH +: ADDR_WIDTH]), .m_axi_arlen(m_axi_arlen[n*8 +: 8]), .m_axi_arsize(m_axi_arsize[n*3 +: 3]), .m_axi_arburst(m_axi_arburst[n*2 +: 2]), .m_axi_arlock(m_axi_arlock[n]), .m_axi_arcache(m_axi_arcache[n*4 +: 4]), .m_axi_arprot(m_axi_arprot[n*3 +: 3]), .m_axi_arqos(m_axi_arqos[n*4 +: 4]), .m_axi_arregion(m_axi_arregion[n*4 +: 4]), .m_axi_aruser(m_axi_aruser[n*ARUSER_WIDTH +: ARUSER_WIDTH]), .m_axi_arvalid(m_axi_arvalid[n]), .m_axi_arready(m_axi_arready[n]), .m_axi_rid(m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH]), .m_axi_rdata(m_axi_rdata[n*DATA_WIDTH +: DATA_WIDTH]), .m_axi_rresp(m_axi_rresp[n*2 +: 2]), .m_axi_rlast(m_axi_rlast[n]), .m_axi_ruser(m_axi_ruser[n*RUSER_WIDTH +: RUSER_WIDTH]), .m_axi_rvalid(m_axi_rvalid[n]), .m_axi_rready(m_axi_rready[n]) ); end // m_ifaces endgenerate endmodule `resetall ================================================ FILE: testbench/axi4_mux/axi_crossbar_wr.v ================================================ /* Copyright (c) 2018 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * AXI4 crossbar (write) */ module axi_crossbar_wr # ( // Number of AXI inputs (slave interfaces) parameter S_COUNT = 4, // Number of AXI outputs (master interfaces) parameter M_COUNT = 4, // Width of data bus in bits parameter DATA_WIDTH = 32, // Width of address bus in bits parameter ADDR_WIDTH = 32, // Width of wstrb (width of data bus in words) parameter STRB_WIDTH = (DATA_WIDTH/8), // Input ID field width (from AXI masters) parameter S_ID_WIDTH = 8, // Output ID field width (towards AXI slaves) // Additional bits required for response routing parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT), // Propagate awuser signal parameter AWUSER_ENABLE = 0, // Width of awuser signal parameter AWUSER_WIDTH = 1, // Propagate wuser signal parameter WUSER_ENABLE = 0, // Width of wuser signal parameter WUSER_WIDTH = 1, // Propagate buser signal parameter BUSER_ENABLE = 0, // Width of buser signal parameter BUSER_WIDTH = 1, // Number of concurrent unique IDs for each slave interface // S_COUNT concatenated fields of 32 bits parameter S_THREADS = {S_COUNT{32'd2}}, // Number of concurrent operations for each slave interface // S_COUNT concatenated fields of 32 bits parameter S_ACCEPT = {S_COUNT{32'd16}}, // Number of regions per master interface parameter M_REGIONS = 1, // Master interface base addresses // M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits // set to zero for default addressing based on M_ADDR_WIDTH parameter M_BASE_ADDR = 0, // Master interface address widths // M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}}, // Write connections between interfaces // M_COUNT concatenated fields of S_COUNT bits parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}}, // Number of concurrent operations for each master interface // M_COUNT concatenated fields of 32 bits parameter M_ISSUE = {M_COUNT{32'd4}}, // Secure master (fail operations based on awprot/arprot) // M_COUNT bits parameter M_SECURE = {M_COUNT{1'b0}}, // Slave interface AW channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_AW_REG_TYPE = {S_COUNT{2'd0}}, // Slave interface W channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_W_REG_TYPE = {S_COUNT{2'd0}}, // Slave interface B channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S_B_REG_TYPE = {S_COUNT{2'd1}}, // Master interface AW channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_AW_REG_TYPE = {M_COUNT{2'd1}}, // Master interface W channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_W_REG_TYPE = {M_COUNT{2'd2}}, // Master interface B channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M_B_REG_TYPE = {M_COUNT{2'd0}} ) ( input wire clk, input wire rst, /* * AXI slave interfaces */ input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_awid, input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_awaddr, input wire [S_COUNT*8-1:0] s_axi_awlen, input wire [S_COUNT*3-1:0] s_axi_awsize, input wire [S_COUNT*2-1:0] s_axi_awburst, input wire [S_COUNT-1:0] s_axi_awlock, input wire [S_COUNT*4-1:0] s_axi_awcache, input wire [S_COUNT*3-1:0] s_axi_awprot, input wire [S_COUNT*4-1:0] s_axi_awqos, input wire [S_COUNT*AWUSER_WIDTH-1:0] s_axi_awuser, input wire [S_COUNT-1:0] s_axi_awvalid, output wire [S_COUNT-1:0] s_axi_awready, input wire [S_COUNT*DATA_WIDTH-1:0] s_axi_wdata, input wire [S_COUNT*STRB_WIDTH-1:0] s_axi_wstrb, input wire [S_COUNT-1:0] s_axi_wlast, input wire [S_COUNT*WUSER_WIDTH-1:0] s_axi_wuser, input wire [S_COUNT-1:0] s_axi_wvalid, output wire [S_COUNT-1:0] s_axi_wready, output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_bid, output wire [S_COUNT*2-1:0] s_axi_bresp, output wire [S_COUNT*BUSER_WIDTH-1:0] s_axi_buser, output wire [S_COUNT-1:0] s_axi_bvalid, input wire [S_COUNT-1:0] s_axi_bready, /* * AXI master interfaces */ output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_awid, output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_awaddr, output wire [M_COUNT*8-1:0] m_axi_awlen, output wire [M_COUNT*3-1:0] m_axi_awsize, output wire [M_COUNT*2-1:0] m_axi_awburst, output wire [M_COUNT-1:0] m_axi_awlock, output wire [M_COUNT*4-1:0] m_axi_awcache, output wire [M_COUNT*3-1:0] m_axi_awprot, output wire [M_COUNT*4-1:0] m_axi_awqos, output wire [M_COUNT*4-1:0] m_axi_awregion, output wire [M_COUNT*AWUSER_WIDTH-1:0] m_axi_awuser, output wire [M_COUNT-1:0] m_axi_awvalid, input wire [M_COUNT-1:0] m_axi_awready, output wire [M_COUNT*DATA_WIDTH-1:0] m_axi_wdata, output wire [M_COUNT*STRB_WIDTH-1:0] m_axi_wstrb, output wire [M_COUNT-1:0] m_axi_wlast, output wire [M_COUNT*WUSER_WIDTH-1:0] m_axi_wuser, output wire [M_COUNT-1:0] m_axi_wvalid, input wire [M_COUNT-1:0] m_axi_wready, input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_bid, input wire [M_COUNT*2-1:0] m_axi_bresp, input wire [M_COUNT*BUSER_WIDTH-1:0] m_axi_buser, input wire [M_COUNT-1:0] m_axi_bvalid, output wire [M_COUNT-1:0] m_axi_bready ); parameter CL_S_COUNT = $clog2(S_COUNT); parameter CL_M_COUNT = $clog2(M_COUNT); parameter M_COUNT_P1 = M_COUNT+1; parameter CL_M_COUNT_P1 = $clog2(M_COUNT_P1); integer i; // check configuration initial begin if (M_ID_WIDTH < S_ID_WIDTH+$clog2(S_COUNT)) begin $error("Error: M_ID_WIDTH must be at least $clog2(S_COUNT) larger than S_ID_WIDTH (instance %m)"); $finish; end for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin $error("Error: value out of range (instance %m)"); $finish; end end end wire [S_COUNT*S_ID_WIDTH-1:0] int_s_axi_awid; wire [S_COUNT*ADDR_WIDTH-1:0] int_s_axi_awaddr; wire [S_COUNT*8-1:0] int_s_axi_awlen; wire [S_COUNT*3-1:0] int_s_axi_awsize; wire [S_COUNT*2-1:0] int_s_axi_awburst; wire [S_COUNT-1:0] int_s_axi_awlock; wire [S_COUNT*4-1:0] int_s_axi_awcache; wire [S_COUNT*3-1:0] int_s_axi_awprot; wire [S_COUNT*4-1:0] int_s_axi_awqos; wire [S_COUNT*4-1:0] int_s_axi_awregion; wire [S_COUNT*AWUSER_WIDTH-1:0] int_s_axi_awuser; wire [S_COUNT-1:0] int_s_axi_awvalid; wire [S_COUNT-1:0] int_s_axi_awready; wire [S_COUNT*M_COUNT-1:0] int_axi_awvalid; wire [M_COUNT*S_COUNT-1:0] int_axi_awready; wire [S_COUNT*DATA_WIDTH-1:0] int_s_axi_wdata; wire [S_COUNT*STRB_WIDTH-1:0] int_s_axi_wstrb; wire [S_COUNT-1:0] int_s_axi_wlast; wire [S_COUNT*WUSER_WIDTH-1:0] int_s_axi_wuser; wire [S_COUNT-1:0] int_s_axi_wvalid; wire [S_COUNT-1:0] int_s_axi_wready; wire [S_COUNT*M_COUNT-1:0] int_axi_wvalid; wire [M_COUNT*S_COUNT-1:0] int_axi_wready; wire [M_COUNT*M_ID_WIDTH-1:0] int_m_axi_bid; wire [M_COUNT*2-1:0] int_m_axi_bresp; wire [M_COUNT*BUSER_WIDTH-1:0] int_m_axi_buser; wire [M_COUNT-1:0] int_m_axi_bvalid; wire [M_COUNT-1:0] int_m_axi_bready; wire [M_COUNT*S_COUNT-1:0] int_axi_bvalid; wire [S_COUNT*M_COUNT-1:0] int_axi_bready; generate genvar m, n; for (m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces // address decode and admission control wire [CL_M_COUNT-1:0] a_select; wire m_axi_avalid; wire m_axi_aready; wire [CL_M_COUNT-1:0] m_wc_select; wire m_wc_decerr; wire m_wc_valid; wire m_wc_ready; wire m_rc_decerr; wire m_rc_valid; wire m_rc_ready; wire [S_ID_WIDTH-1:0] s_cpl_id; wire s_cpl_valid; axi_crossbar_addr #( .S(m), .S_COUNT(S_COUNT), .M_COUNT(M_COUNT), .ADDR_WIDTH(ADDR_WIDTH), .ID_WIDTH(S_ID_WIDTH), .S_THREADS(S_THREADS[m*32 +: 32]), .S_ACCEPT(S_ACCEPT[m*32 +: 32]), .M_REGIONS(M_REGIONS), .M_BASE_ADDR(M_BASE_ADDR), .M_ADDR_WIDTH(M_ADDR_WIDTH), .M_CONNECT(M_CONNECT), .M_SECURE(M_SECURE), .WC_OUTPUT(1) ) addr_inst ( .clk(clk), .rst(rst), /* * Address input */ .s_axi_aid(int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]), .s_axi_aaddr(int_s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]), .s_axi_aprot(int_s_axi_awprot[m*3 +: 3]), .s_axi_aqos(int_s_axi_awqos[m*4 +: 4]), .s_axi_avalid(int_s_axi_awvalid[m]), .s_axi_aready(int_s_axi_awready[m]), /* * Address output */ .m_axi_aregion(int_s_axi_awregion[m*4 +: 4]), .m_select(a_select), .m_axi_avalid(m_axi_avalid), .m_axi_aready(m_axi_aready), /* * Write command output */ .m_wc_select(m_wc_select), .m_wc_decerr(m_wc_decerr), .m_wc_valid(m_wc_valid), .m_wc_ready(m_wc_ready), /* * Response command output */ .m_rc_decerr(m_rc_decerr), .m_rc_valid(m_rc_valid), .m_rc_ready(m_rc_ready), /* * Completion input */ .s_cpl_id(s_cpl_id), .s_cpl_valid(s_cpl_valid) ); assign int_axi_awvalid[m*M_COUNT +: M_COUNT] = m_axi_avalid << a_select; assign m_axi_aready = int_axi_awready[a_select*S_COUNT+m]; // write command handling reg [CL_M_COUNT-1:0] w_select_reg = 0, w_select_next; reg w_drop_reg = 1'b0, w_drop_next; reg w_select_valid_reg = 1'b0, w_select_valid_next; assign m_wc_ready = !w_select_valid_reg; always @* begin w_select_next = w_select_reg; w_drop_next = w_drop_reg && !(int_s_axi_wvalid[m] && int_s_axi_wready[m] && int_s_axi_wlast[m]); w_select_valid_next = w_select_valid_reg && !(int_s_axi_wvalid[m] && int_s_axi_wready[m] && int_s_axi_wlast[m]); if (m_wc_valid && !w_select_valid_reg) begin w_select_next = m_wc_select; w_drop_next = m_wc_decerr; w_select_valid_next = m_wc_valid; end end always @(posedge clk) begin if (rst) begin w_select_valid_reg <= 1'b0; end else begin w_select_valid_reg <= w_select_valid_next; end w_select_reg <= w_select_next; w_drop_reg <= w_drop_next; end // write data forwarding assign int_axi_wvalid[m*M_COUNT +: M_COUNT] = (int_s_axi_wvalid[m] && w_select_valid_reg && !w_drop_reg) << w_select_reg; assign int_s_axi_wready[m] = int_axi_wready[w_select_reg*S_COUNT+m] || w_drop_reg; // decode error handling reg [S_ID_WIDTH-1:0] decerr_m_axi_bid_reg = {S_ID_WIDTH{1'b0}}, decerr_m_axi_bid_next; reg decerr_m_axi_bvalid_reg = 1'b0, decerr_m_axi_bvalid_next; wire decerr_m_axi_bready; assign m_rc_ready = !decerr_m_axi_bvalid_reg; always @* begin decerr_m_axi_bid_next = decerr_m_axi_bid_reg; decerr_m_axi_bvalid_next = decerr_m_axi_bvalid_reg; if (decerr_m_axi_bvalid_reg) begin if (decerr_m_axi_bready) begin decerr_m_axi_bvalid_next = 1'b0; end end else if (m_rc_valid && m_rc_ready) begin decerr_m_axi_bid_next = int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]; decerr_m_axi_bvalid_next = 1'b1; end end always @(posedge clk) begin if (rst) begin decerr_m_axi_bvalid_reg <= 1'b0; end else begin decerr_m_axi_bvalid_reg <= decerr_m_axi_bvalid_next; end decerr_m_axi_bid_reg <= decerr_m_axi_bid_next; end // write response arbitration wire [M_COUNT_P1-1:0] b_request; wire [M_COUNT_P1-1:0] b_acknowledge; wire [M_COUNT_P1-1:0] b_grant; wire b_grant_valid; wire [CL_M_COUNT_P1-1:0] b_grant_encoded; arbiter #( .PORTS(M_COUNT_P1), .ARB_TYPE_ROUND_ROBIN(1), .ARB_BLOCK(1), .ARB_BLOCK_ACK(1), .ARB_LSB_HIGH_PRIORITY(1) ) b_arb_inst ( .clk(clk), .rst(rst), .request(b_request), .acknowledge(b_acknowledge), .grant(b_grant), .grant_valid(b_grant_valid), .grant_encoded(b_grant_encoded) ); // write response mux wire [S_ID_WIDTH-1:0] m_axi_bid_mux = {decerr_m_axi_bid_reg, int_m_axi_bid} >> b_grant_encoded*M_ID_WIDTH; wire [1:0] m_axi_bresp_mux = {2'b11, int_m_axi_bresp} >> b_grant_encoded*2; wire [BUSER_WIDTH-1:0] m_axi_buser_mux = {{BUSER_WIDTH{1'b0}}, int_m_axi_buser} >> b_grant_encoded*BUSER_WIDTH; wire m_axi_bvalid_mux = ({decerr_m_axi_bvalid_reg, int_m_axi_bvalid} >> b_grant_encoded) & b_grant_valid; wire m_axi_bready_mux; assign int_axi_bready[m*M_COUNT +: M_COUNT] = (b_grant_valid && m_axi_bready_mux) << b_grant_encoded; assign decerr_m_axi_bready = (b_grant_valid && m_axi_bready_mux) && (b_grant_encoded == M_COUNT_P1-1); for (n = 0; n < M_COUNT; n = n + 1) begin assign b_request[n] = int_axi_bvalid[n*S_COUNT+m] && !b_grant[n]; assign b_acknowledge[n] = b_grant[n] && int_axi_bvalid[n*S_COUNT+m] && m_axi_bready_mux; end assign b_request[M_COUNT_P1-1] = decerr_m_axi_bvalid_reg && !b_grant[M_COUNT_P1-1]; assign b_acknowledge[M_COUNT_P1-1] = b_grant[M_COUNT_P1-1] && decerr_m_axi_bvalid_reg && m_axi_bready_mux; assign s_cpl_id = m_axi_bid_mux; assign s_cpl_valid = m_axi_bvalid_mux && m_axi_bready_mux; // S side register axi_register_wr #( .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .STRB_WIDTH(STRB_WIDTH), .ID_WIDTH(S_ID_WIDTH), .AWUSER_ENABLE(AWUSER_ENABLE), .AWUSER_WIDTH(AWUSER_WIDTH), .WUSER_ENABLE(WUSER_ENABLE), .WUSER_WIDTH(WUSER_WIDTH), .BUSER_ENABLE(BUSER_ENABLE), .BUSER_WIDTH(BUSER_WIDTH), .AW_REG_TYPE(S_AW_REG_TYPE[m*2 +: 2]), .W_REG_TYPE(S_W_REG_TYPE[m*2 +: 2]), .B_REG_TYPE(S_B_REG_TYPE[m*2 +: 2]) ) reg_inst ( .clk(clk), .rst(rst), .s_axi_awid(s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]), .s_axi_awaddr(s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]), .s_axi_awlen(s_axi_awlen[m*8 +: 8]), .s_axi_awsize(s_axi_awsize[m*3 +: 3]), .s_axi_awburst(s_axi_awburst[m*2 +: 2]), .s_axi_awlock(s_axi_awlock[m]), .s_axi_awcache(s_axi_awcache[m*4 +: 4]), .s_axi_awprot(s_axi_awprot[m*3 +: 3]), .s_axi_awqos(s_axi_awqos[m*4 +: 4]), .s_axi_awregion(4'd0), .s_axi_awuser(s_axi_awuser[m*AWUSER_WIDTH +: AWUSER_WIDTH]), .s_axi_awvalid(s_axi_awvalid[m]), .s_axi_awready(s_axi_awready[m]), .s_axi_wdata(s_axi_wdata[m*DATA_WIDTH +: DATA_WIDTH]), .s_axi_wstrb(s_axi_wstrb[m*STRB_WIDTH +: STRB_WIDTH]), .s_axi_wlast(s_axi_wlast[m]), .s_axi_wuser(s_axi_wuser[m*WUSER_WIDTH +: WUSER_WIDTH]), .s_axi_wvalid(s_axi_wvalid[m]), .s_axi_wready(s_axi_wready[m]), .s_axi_bid(s_axi_bid[m*S_ID_WIDTH +: S_ID_WIDTH]), .s_axi_bresp(s_axi_bresp[m*2 +: 2]), .s_axi_buser(s_axi_buser[m*BUSER_WIDTH +: BUSER_WIDTH]), .s_axi_bvalid(s_axi_bvalid[m]), .s_axi_bready(s_axi_bready[m]), .m_axi_awid(int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]), .m_axi_awaddr(int_s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]), .m_axi_awlen(int_s_axi_awlen[m*8 +: 8]), .m_axi_awsize(int_s_axi_awsize[m*3 +: 3]), .m_axi_awburst(int_s_axi_awburst[m*2 +: 2]), .m_axi_awlock(int_s_axi_awlock[m]), .m_axi_awcache(int_s_axi_awcache[m*4 +: 4]), .m_axi_awprot(int_s_axi_awprot[m*3 +: 3]), .m_axi_awqos(int_s_axi_awqos[m*4 +: 4]), .m_axi_awregion(), .m_axi_awuser(int_s_axi_awuser[m*AWUSER_WIDTH +: AWUSER_WIDTH]), .m_axi_awvalid(int_s_axi_awvalid[m]), .m_axi_awready(int_s_axi_awready[m]), .m_axi_wdata(int_s_axi_wdata[m*DATA_WIDTH +: DATA_WIDTH]), .m_axi_wstrb(int_s_axi_wstrb[m*STRB_WIDTH +: STRB_WIDTH]), .m_axi_wlast(int_s_axi_wlast[m]), .m_axi_wuser(int_s_axi_wuser[m*WUSER_WIDTH +: WUSER_WIDTH]), .m_axi_wvalid(int_s_axi_wvalid[m]), .m_axi_wready(int_s_axi_wready[m]), .m_axi_bid(m_axi_bid_mux), .m_axi_bresp(m_axi_bresp_mux), .m_axi_buser(m_axi_buser_mux), .m_axi_bvalid(m_axi_bvalid_mux), .m_axi_bready(m_axi_bready_mux) ); end // s_ifaces for (n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces // in-flight transaction count wire trans_start; wire trans_complete; reg [$clog2(M_ISSUE[n*32 +: 32]+1)-1:0] trans_count_reg = 0; wire trans_limit = trans_count_reg >= M_ISSUE[n*32 +: 32] && !trans_complete; always @(posedge clk) begin if (rst) begin trans_count_reg <= 0; end else begin if (trans_start && !trans_complete) begin trans_count_reg <= trans_count_reg + 1; end else if (!trans_start && trans_complete) begin trans_count_reg <= trans_count_reg - 1; end end end // address arbitration reg [CL_S_COUNT-1:0] w_select_reg = 0, w_select_next; reg w_select_valid_reg = 1'b0, w_select_valid_next; reg w_select_new_reg = 1'b0, w_select_new_next; wire [S_COUNT-1:0] a_request; wire [S_COUNT-1:0] a_acknowledge; wire [S_COUNT-1:0] a_grant; wire a_grant_valid; wire [CL_S_COUNT-1:0] a_grant_encoded; arbiter #( .PORTS(S_COUNT), .ARB_TYPE_ROUND_ROBIN(1), .ARB_BLOCK(1), .ARB_BLOCK_ACK(1), .ARB_LSB_HIGH_PRIORITY(1) ) a_arb_inst ( .clk(clk), .rst(rst), .request(a_request), .acknowledge(a_acknowledge), .grant(a_grant), .grant_valid(a_grant_valid), .grant_encoded(a_grant_encoded) ); // address mux wire [M_ID_WIDTH-1:0] s_axi_awid_mux = int_s_axi_awid[a_grant_encoded*S_ID_WIDTH +: S_ID_WIDTH] | (a_grant_encoded << S_ID_WIDTH); wire [ADDR_WIDTH-1:0] s_axi_awaddr_mux = int_s_axi_awaddr[a_grant_encoded*ADDR_WIDTH +: ADDR_WIDTH]; wire [7:0] s_axi_awlen_mux = int_s_axi_awlen[a_grant_encoded*8 +: 8]; wire [2:0] s_axi_awsize_mux = int_s_axi_awsize[a_grant_encoded*3 +: 3]; wire [1:0] s_axi_awburst_mux = int_s_axi_awburst[a_grant_encoded*2 +: 2]; wire s_axi_awlock_mux = int_s_axi_awlock[a_grant_encoded]; wire [3:0] s_axi_awcache_mux = int_s_axi_awcache[a_grant_encoded*4 +: 4]; wire [2:0] s_axi_awprot_mux = int_s_axi_awprot[a_grant_encoded*3 +: 3]; wire [3:0] s_axi_awqos_mux = int_s_axi_awqos[a_grant_encoded*4 +: 4]; wire [3:0] s_axi_awregion_mux = int_s_axi_awregion[a_grant_encoded*4 +: 4]; wire [AWUSER_WIDTH-1:0] s_axi_awuser_mux = int_s_axi_awuser[a_grant_encoded*AWUSER_WIDTH +: AWUSER_WIDTH]; wire s_axi_awvalid_mux = int_axi_awvalid[a_grant_encoded*M_COUNT+n] && a_grant_valid; wire s_axi_awready_mux; assign int_axi_awready[n*S_COUNT +: S_COUNT] = (a_grant_valid && s_axi_awready_mux) << a_grant_encoded; for (m = 0; m < S_COUNT; m = m + 1) begin assign a_request[m] = int_axi_awvalid[m*M_COUNT+n] && !a_grant[m] && !trans_limit && !w_select_valid_next; assign a_acknowledge[m] = a_grant[m] && int_axi_awvalid[m*M_COUNT+n] && s_axi_awready_mux; end assign trans_start = s_axi_awvalid_mux && s_axi_awready_mux && a_grant_valid; // write data mux wire [DATA_WIDTH-1:0] s_axi_wdata_mux = int_s_axi_wdata[w_select_reg*DATA_WIDTH +: DATA_WIDTH]; wire [STRB_WIDTH-1:0] s_axi_wstrb_mux = int_s_axi_wstrb[w_select_reg*STRB_WIDTH +: STRB_WIDTH]; wire s_axi_wlast_mux = int_s_axi_wlast[w_select_reg]; wire [WUSER_WIDTH-1:0] s_axi_wuser_mux = int_s_axi_wuser[w_select_reg*WUSER_WIDTH +: WUSER_WIDTH]; wire s_axi_wvalid_mux = int_axi_wvalid[w_select_reg*M_COUNT+n] && w_select_valid_reg; wire s_axi_wready_mux; assign int_axi_wready[n*S_COUNT +: S_COUNT] = (w_select_valid_reg && s_axi_wready_mux) << w_select_reg; // write data routing always @* begin w_select_next = w_select_reg; w_select_valid_next = w_select_valid_reg && !(s_axi_wvalid_mux && s_axi_wready_mux && s_axi_wlast_mux); w_select_new_next = w_select_new_reg || !a_grant_valid || a_acknowledge; if (a_grant_valid && !w_select_valid_reg && w_select_new_reg) begin w_select_next = a_grant_encoded; w_select_valid_next = a_grant_valid; w_select_new_next = 1'b0; end end always @(posedge clk) begin if (rst) begin w_select_valid_reg <= 1'b0; w_select_new_reg <= 1'b1; end else begin w_select_valid_reg <= w_select_valid_next; w_select_new_reg <= w_select_new_next; end w_select_reg <= w_select_next; end // write response forwarding wire [CL_S_COUNT-1:0] b_select = m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH] >> S_ID_WIDTH; assign int_axi_bvalid[n*S_COUNT +: S_COUNT] = int_m_axi_bvalid[n] << b_select; assign int_m_axi_bready[n] = int_axi_bready[b_select*M_COUNT+n]; assign trans_complete = int_m_axi_bvalid[n] && int_m_axi_bready[n]; // M side register axi_register_wr #( .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .STRB_WIDTH(STRB_WIDTH), .ID_WIDTH(M_ID_WIDTH), .AWUSER_ENABLE(AWUSER_ENABLE), .AWUSER_WIDTH(AWUSER_WIDTH), .WUSER_ENABLE(WUSER_ENABLE), .WUSER_WIDTH(WUSER_WIDTH), .BUSER_ENABLE(BUSER_ENABLE), .BUSER_WIDTH(BUSER_WIDTH), .AW_REG_TYPE(M_AW_REG_TYPE[n*2 +: 2]), .W_REG_TYPE(M_W_REG_TYPE[n*2 +: 2]), .B_REG_TYPE(M_B_REG_TYPE[n*2 +: 2]) ) reg_inst ( .clk(clk), .rst(rst), .s_axi_awid(s_axi_awid_mux), .s_axi_awaddr(s_axi_awaddr_mux), .s_axi_awlen(s_axi_awlen_mux), .s_axi_awsize(s_axi_awsize_mux), .s_axi_awburst(s_axi_awburst_mux), .s_axi_awlock(s_axi_awlock_mux), .s_axi_awcache(s_axi_awcache_mux), .s_axi_awprot(s_axi_awprot_mux), .s_axi_awqos(s_axi_awqos_mux), .s_axi_awregion(s_axi_awregion_mux), .s_axi_awuser(s_axi_awuser_mux), .s_axi_awvalid(s_axi_awvalid_mux), .s_axi_awready(s_axi_awready_mux), .s_axi_wdata(s_axi_wdata_mux), .s_axi_wstrb(s_axi_wstrb_mux), .s_axi_wlast(s_axi_wlast_mux), .s_axi_wuser(s_axi_wuser_mux), .s_axi_wvalid(s_axi_wvalid_mux), .s_axi_wready(s_axi_wready_mux), .s_axi_bid(int_m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH]), .s_axi_bresp(int_m_axi_bresp[n*2 +: 2]), .s_axi_buser(int_m_axi_buser[n*BUSER_WIDTH +: BUSER_WIDTH]), .s_axi_bvalid(int_m_axi_bvalid[n]), .s_axi_bready(int_m_axi_bready[n]), .m_axi_awid(m_axi_awid[n*M_ID_WIDTH +: M_ID_WIDTH]), .m_axi_awaddr(m_axi_awaddr[n*ADDR_WIDTH +: ADDR_WIDTH]), .m_axi_awlen(m_axi_awlen[n*8 +: 8]), .m_axi_awsize(m_axi_awsize[n*3 +: 3]), .m_axi_awburst(m_axi_awburst[n*2 +: 2]), .m_axi_awlock(m_axi_awlock[n]), .m_axi_awcache(m_axi_awcache[n*4 +: 4]), .m_axi_awprot(m_axi_awprot[n*3 +: 3]), .m_axi_awqos(m_axi_awqos[n*4 +: 4]), .m_axi_awregion(m_axi_awregion[n*4 +: 4]), .m_axi_awuser(m_axi_awuser[n*AWUSER_WIDTH +: AWUSER_WIDTH]), .m_axi_awvalid(m_axi_awvalid[n]), .m_axi_awready(m_axi_awready[n]), .m_axi_wdata(m_axi_wdata[n*DATA_WIDTH +: DATA_WIDTH]), .m_axi_wstrb(m_axi_wstrb[n*STRB_WIDTH +: STRB_WIDTH]), .m_axi_wlast(m_axi_wlast[n]), .m_axi_wuser(m_axi_wuser[n*WUSER_WIDTH +: WUSER_WIDTH]), .m_axi_wvalid(m_axi_wvalid[n]), .m_axi_wready(m_axi_wready[n]), .m_axi_bid(m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH]), .m_axi_bresp(m_axi_bresp[n*2 +: 2]), .m_axi_buser(m_axi_buser[n*BUSER_WIDTH +: BUSER_WIDTH]), .m_axi_bvalid(m_axi_bvalid[n]), .m_axi_bready(m_axi_bready[n]) ); end // m_ifaces endgenerate endmodule `resetall ================================================ FILE: testbench/axi4_mux/axi_crossbar_wrap_2x1.v ================================================ /* Copyright (c) 2020 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * AXI4 2x1 crossbar (wrapper) */ module axi_crossbar_wrap_2x1 # ( parameter S_COUNT = 2, parameter M_COUNT = 1, // Width of data bus in bits parameter DATA_WIDTH = 32, // Width of address bus in bits parameter ADDR_WIDTH = 32, // Width of wstrb (width of data bus in words) parameter STRB_WIDTH = (DATA_WIDTH/8), // Input ID field width (from AXI masters) parameter S_ID_WIDTH = 8, // Output ID field width (towards AXI slaves) // Additional bits required for response routing parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT), // Propagate awuser signal parameter AWUSER_ENABLE = 0, // Width of awuser signal parameter AWUSER_WIDTH = 1, // Propagate wuser signal parameter WUSER_ENABLE = 0, // Width of wuser signal parameter WUSER_WIDTH = 1, // Propagate buser signal parameter BUSER_ENABLE = 0, // Width of buser signal parameter BUSER_WIDTH = 1, // Propagate aruser signal parameter ARUSER_ENABLE = 0, // Width of aruser signal parameter ARUSER_WIDTH = 1, // Propagate ruser signal parameter RUSER_ENABLE = 0, // Width of ruser signal parameter RUSER_WIDTH = 1, // Number of concurrent unique IDs parameter S00_THREADS = 2, // Number of concurrent operations parameter S00_ACCEPT = 16, // Number of concurrent unique IDs parameter S01_THREADS = 2, // Number of concurrent operations parameter S01_ACCEPT = 16, // Number of regions per master interface parameter M_REGIONS = 1, // Master interface base addresses // M_REGIONS concatenated fields of ADDR_WIDTH bits parameter M00_BASE_ADDR = 0, // Master interface address widths // M_REGIONS concatenated fields of 32 bits parameter M00_ADDR_WIDTH = {M_REGIONS{32'd24}}, // Read connections between interfaces // S_COUNT bits parameter M00_CONNECT_READ = 2'b11, // Write connections between interfaces // S_COUNT bits parameter M00_CONNECT_WRITE = 2'b11, // Number of concurrent operations for each master interface parameter M00_ISSUE = 4, // Secure master (fail operations based on awprot/arprot) parameter M00_SECURE = 0, // Slave interface AW channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S00_AW_REG_TYPE = 0, // Slave interface W channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S00_W_REG_TYPE = 0, // Slave interface B channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S00_B_REG_TYPE = 1, // Slave interface AR channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S00_AR_REG_TYPE = 0, // Slave interface R channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S00_R_REG_TYPE = 2, // Slave interface AW channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S01_AW_REG_TYPE = 0, // Slave interface W channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S01_W_REG_TYPE = 0, // Slave interface B channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S01_B_REG_TYPE = 1, // Slave interface AR channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S01_AR_REG_TYPE = 0, // Slave interface R channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter S01_R_REG_TYPE = 2, // Master interface AW channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M00_AW_REG_TYPE = 1, // Master interface W channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M00_W_REG_TYPE = 2, // Master interface B channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M00_B_REG_TYPE = 0, // Master interface AR channel register type (output) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M00_AR_REG_TYPE = 1, // Master interface R channel register type (input) // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter M00_R_REG_TYPE = 0 ) ( input wire clk, input wire rst, /* * AXI slave interface */ input wire [S_ID_WIDTH-1:0] s00_axi_awid, input wire [ADDR_WIDTH-1:0] s00_axi_awaddr, input wire [7:0] s00_axi_awlen, input wire [2:0] s00_axi_awsize, input wire [1:0] s00_axi_awburst, input wire s00_axi_awlock, input wire [3:0] s00_axi_awcache, input wire [2:0] s00_axi_awprot, input wire [3:0] s00_axi_awqos, input wire [AWUSER_WIDTH-1:0] s00_axi_awuser, input wire s00_axi_awvalid, output wire s00_axi_awready, input wire [DATA_WIDTH-1:0] s00_axi_wdata, input wire [STRB_WIDTH-1:0] s00_axi_wstrb, input wire s00_axi_wlast, input wire [WUSER_WIDTH-1:0] s00_axi_wuser, input wire s00_axi_wvalid, output wire s00_axi_wready, output wire [S_ID_WIDTH-1:0] s00_axi_bid, output wire [1:0] s00_axi_bresp, output wire [BUSER_WIDTH-1:0] s00_axi_buser, output wire s00_axi_bvalid, input wire s00_axi_bready, input wire [S_ID_WIDTH-1:0] s00_axi_arid, input wire [ADDR_WIDTH-1:0] s00_axi_araddr, input wire [7:0] s00_axi_arlen, input wire [2:0] s00_axi_arsize, input wire [1:0] s00_axi_arburst, input wire s00_axi_arlock, input wire [3:0] s00_axi_arcache, input wire [2:0] s00_axi_arprot, input wire [3:0] s00_axi_arqos, input wire [ARUSER_WIDTH-1:0] s00_axi_aruser, input wire s00_axi_arvalid, output wire s00_axi_arready, output wire [S_ID_WIDTH-1:0] s00_axi_rid, output wire [DATA_WIDTH-1:0] s00_axi_rdata, output wire [1:0] s00_axi_rresp, output wire s00_axi_rlast, output wire [RUSER_WIDTH-1:0] s00_axi_ruser, output wire s00_axi_rvalid, input wire s00_axi_rready, input wire [S_ID_WIDTH-1:0] s01_axi_awid, input wire [ADDR_WIDTH-1:0] s01_axi_awaddr, input wire [7:0] s01_axi_awlen, input wire [2:0] s01_axi_awsize, input wire [1:0] s01_axi_awburst, input wire s01_axi_awlock, input wire [3:0] s01_axi_awcache, input wire [2:0] s01_axi_awprot, input wire [3:0] s01_axi_awqos, input wire [AWUSER_WIDTH-1:0] s01_axi_awuser, input wire s01_axi_awvalid, output wire s01_axi_awready, input wire [DATA_WIDTH-1:0] s01_axi_wdata, input wire [STRB_WIDTH-1:0] s01_axi_wstrb, input wire s01_axi_wlast, input wire [WUSER_WIDTH-1:0] s01_axi_wuser, input wire s01_axi_wvalid, output wire s01_axi_wready, output wire [S_ID_WIDTH-1:0] s01_axi_bid, output wire [1:0] s01_axi_bresp, output wire [BUSER_WIDTH-1:0] s01_axi_buser, output wire s01_axi_bvalid, input wire s01_axi_bready, input wire [S_ID_WIDTH-1:0] s01_axi_arid, input wire [ADDR_WIDTH-1:0] s01_axi_araddr, input wire [7:0] s01_axi_arlen, input wire [2:0] s01_axi_arsize, input wire [1:0] s01_axi_arburst, input wire s01_axi_arlock, input wire [3:0] s01_axi_arcache, input wire [2:0] s01_axi_arprot, input wire [3:0] s01_axi_arqos, input wire [ARUSER_WIDTH-1:0] s01_axi_aruser, input wire s01_axi_arvalid, output wire s01_axi_arready, output wire [S_ID_WIDTH-1:0] s01_axi_rid, output wire [DATA_WIDTH-1:0] s01_axi_rdata, output wire [1:0] s01_axi_rresp, output wire s01_axi_rlast, output wire [RUSER_WIDTH-1:0] s01_axi_ruser, output wire s01_axi_rvalid, input wire s01_axi_rready, /* * AXI master interface */ output wire [M_ID_WIDTH-1:0] m00_axi_awid, output wire [ADDR_WIDTH-1:0] m00_axi_awaddr, output wire [7:0] m00_axi_awlen, output wire [2:0] m00_axi_awsize, output wire [1:0] m00_axi_awburst, output wire m00_axi_awlock, output wire [3:0] m00_axi_awcache, output wire [2:0] m00_axi_awprot, output wire [3:0] m00_axi_awqos, output wire [3:0] m00_axi_awregion, output wire [AWUSER_WIDTH-1:0] m00_axi_awuser, output wire m00_axi_awvalid, input wire m00_axi_awready, output wire [DATA_WIDTH-1:0] m00_axi_wdata, output wire [STRB_WIDTH-1:0] m00_axi_wstrb, output wire m00_axi_wlast, output wire [WUSER_WIDTH-1:0] m00_axi_wuser, output wire m00_axi_wvalid, input wire m00_axi_wready, input wire [M_ID_WIDTH-1:0] m00_axi_bid, input wire [1:0] m00_axi_bresp, input wire [BUSER_WIDTH-1:0] m00_axi_buser, input wire m00_axi_bvalid, output wire m00_axi_bready, output wire [M_ID_WIDTH-1:0] m00_axi_arid, output wire [ADDR_WIDTH-1:0] m00_axi_araddr, output wire [7:0] m00_axi_arlen, output wire [2:0] m00_axi_arsize, output wire [1:0] m00_axi_arburst, output wire m00_axi_arlock, output wire [3:0] m00_axi_arcache, output wire [2:0] m00_axi_arprot, output wire [3:0] m00_axi_arqos, output wire [3:0] m00_axi_arregion, output wire [ARUSER_WIDTH-1:0] m00_axi_aruser, output wire m00_axi_arvalid, input wire m00_axi_arready, input wire [M_ID_WIDTH-1:0] m00_axi_rid, input wire [DATA_WIDTH-1:0] m00_axi_rdata, input wire [1:0] m00_axi_rresp, input wire m00_axi_rlast, input wire [RUSER_WIDTH-1:0] m00_axi_ruser, input wire m00_axi_rvalid, output wire m00_axi_rready ); // parameter sizing helpers function [ADDR_WIDTH*M_REGIONS-1:0] w_a_r(input [ADDR_WIDTH*M_REGIONS-1:0] val); w_a_r = val; endfunction function [32*M_REGIONS-1:0] w_32_r(input [32*M_REGIONS-1:0] val); w_32_r = val; endfunction function [S_COUNT-1:0] w_s(input [S_COUNT-1:0] val); w_s = val; endfunction function [31:0] w_32(input [31:0] val); w_32 = val; endfunction function [1:0] w_2(input [1:0] val); w_2 = val; endfunction function w_1(input val); w_1 = val; endfunction axi_crossbar #( .S_COUNT(S_COUNT), .M_COUNT(M_COUNT), .DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .STRB_WIDTH(STRB_WIDTH), .S_ID_WIDTH(S_ID_WIDTH), .M_ID_WIDTH(M_ID_WIDTH), .AWUSER_ENABLE(AWUSER_ENABLE), .AWUSER_WIDTH(AWUSER_WIDTH), .WUSER_ENABLE(WUSER_ENABLE), .WUSER_WIDTH(WUSER_WIDTH), .BUSER_ENABLE(BUSER_ENABLE), .BUSER_WIDTH(BUSER_WIDTH), .ARUSER_ENABLE(ARUSER_ENABLE), .ARUSER_WIDTH(ARUSER_WIDTH), .RUSER_ENABLE(RUSER_ENABLE), .RUSER_WIDTH(RUSER_WIDTH), .S_THREADS({ w_32(S01_THREADS), w_32(S00_THREADS) }), .S_ACCEPT({ w_32(S01_ACCEPT), w_32(S00_ACCEPT) }), .M_REGIONS(M_REGIONS), .M_BASE_ADDR({ w_a_r(M00_BASE_ADDR) }), .M_ADDR_WIDTH({ w_32_r(M00_ADDR_WIDTH) }), .M_CONNECT_READ({ w_s(M00_CONNECT_READ) }), .M_CONNECT_WRITE({ w_s(M00_CONNECT_WRITE) }), .M_ISSUE({ w_32(M00_ISSUE) }), .M_SECURE({ w_1(M00_SECURE) }), .S_AR_REG_TYPE({ w_2(S01_AR_REG_TYPE), w_2(S00_AR_REG_TYPE) }), .S_R_REG_TYPE({ w_2(S01_R_REG_TYPE), w_2(S00_R_REG_TYPE) }), .S_AW_REG_TYPE({ w_2(S01_AW_REG_TYPE), w_2(S00_AW_REG_TYPE) }), .S_W_REG_TYPE({ w_2(S01_W_REG_TYPE), w_2(S00_W_REG_TYPE) }), .S_B_REG_TYPE({ w_2(S01_B_REG_TYPE), w_2(S00_B_REG_TYPE) }), .M_AR_REG_TYPE({ w_2(M00_AR_REG_TYPE) }), .M_R_REG_TYPE({ w_2(M00_R_REG_TYPE) }), .M_AW_REG_TYPE({ w_2(M00_AW_REG_TYPE) }), .M_W_REG_TYPE({ w_2(M00_W_REG_TYPE) }), .M_B_REG_TYPE({ w_2(M00_B_REG_TYPE) }) ) axi_crossbar_inst ( .clk(clk), .rst(rst), .s_axi_awid({ s01_axi_awid, s00_axi_awid }), .s_axi_awaddr({ s01_axi_awaddr, s00_axi_awaddr }), .s_axi_awlen({ s01_axi_awlen, s00_axi_awlen }), .s_axi_awsize({ s01_axi_awsize, s00_axi_awsize }), .s_axi_awburst({ s01_axi_awburst, s00_axi_awburst }), .s_axi_awlock({ s01_axi_awlock, s00_axi_awlock }), .s_axi_awcache({ s01_axi_awcache, s00_axi_awcache }), .s_axi_awprot({ s01_axi_awprot, s00_axi_awprot }), .s_axi_awqos({ s01_axi_awqos, s00_axi_awqos }), .s_axi_awuser({ s01_axi_awuser, s00_axi_awuser }), .s_axi_awvalid({ s01_axi_awvalid, s00_axi_awvalid }), .s_axi_awready({ s01_axi_awready, s00_axi_awready }), .s_axi_wdata({ s01_axi_wdata, s00_axi_wdata }), .s_axi_wstrb({ s01_axi_wstrb, s00_axi_wstrb }), .s_axi_wlast({ s01_axi_wlast, s00_axi_wlast }), .s_axi_wuser({ s01_axi_wuser, s00_axi_wuser }), .s_axi_wvalid({ s01_axi_wvalid, s00_axi_wvalid }), .s_axi_wready({ s01_axi_wready, s00_axi_wready }), .s_axi_bid({ s01_axi_bid, s00_axi_bid }), .s_axi_bresp({ s01_axi_bresp, s00_axi_bresp }), .s_axi_buser({ s01_axi_buser, s00_axi_buser }), .s_axi_bvalid({ s01_axi_bvalid, s00_axi_bvalid }), .s_axi_bready({ s01_axi_bready, s00_axi_bready }), .s_axi_arid({ s01_axi_arid, s00_axi_arid }), .s_axi_araddr({ s01_axi_araddr, s00_axi_araddr }), .s_axi_arlen({ s01_axi_arlen, s00_axi_arlen }), .s_axi_arsize({ s01_axi_arsize, s00_axi_arsize }), .s_axi_arburst({ s01_axi_arburst, s00_axi_arburst }), .s_axi_arlock({ s01_axi_arlock, s00_axi_arlock }), .s_axi_arcache({ s01_axi_arcache, s00_axi_arcache }), .s_axi_arprot({ s01_axi_arprot, s00_axi_arprot }), .s_axi_arqos({ s01_axi_arqos, s00_axi_arqos }), .s_axi_aruser({ s01_axi_aruser, s00_axi_aruser }), .s_axi_arvalid({ s01_axi_arvalid, s00_axi_arvalid }), .s_axi_arready({ s01_axi_arready, s00_axi_arready }), .s_axi_rid({ s01_axi_rid, s00_axi_rid }), .s_axi_rdata({ s01_axi_rdata, s00_axi_rdata }), .s_axi_rresp({ s01_axi_rresp, s00_axi_rresp }), .s_axi_rlast({ s01_axi_rlast, s00_axi_rlast }), .s_axi_ruser({ s01_axi_ruser, s00_axi_ruser }), .s_axi_rvalid({ s01_axi_rvalid, s00_axi_rvalid }), .s_axi_rready({ s01_axi_rready, s00_axi_rready }), .m_axi_awid({ m00_axi_awid }), .m_axi_awaddr({ m00_axi_awaddr }), .m_axi_awlen({ m00_axi_awlen }), .m_axi_awsize({ m00_axi_awsize }), .m_axi_awburst({ m00_axi_awburst }), .m_axi_awlock({ m00_axi_awlock }), .m_axi_awcache({ m00_axi_awcache }), .m_axi_awprot({ m00_axi_awprot }), .m_axi_awqos({ m00_axi_awqos }), .m_axi_awregion({ m00_axi_awregion }), .m_axi_awuser({ m00_axi_awuser }), .m_axi_awvalid({ m00_axi_awvalid }), .m_axi_awready({ m00_axi_awready }), .m_axi_wdata({ m00_axi_wdata }), .m_axi_wstrb({ m00_axi_wstrb }), .m_axi_wlast({ m00_axi_wlast }), .m_axi_wuser({ m00_axi_wuser }), .m_axi_wvalid({ m00_axi_wvalid }), .m_axi_wready({ m00_axi_wready }), .m_axi_bid({ m00_axi_bid }), .m_axi_bresp({ m00_axi_bresp }), .m_axi_buser({ m00_axi_buser }), .m_axi_bvalid({ m00_axi_bvalid }), .m_axi_bready({ m00_axi_bready }), .m_axi_arid({ m00_axi_arid }), .m_axi_araddr({ m00_axi_araddr }), .m_axi_arlen({ m00_axi_arlen }), .m_axi_arsize({ m00_axi_arsize }), .m_axi_arburst({ m00_axi_arburst }), .m_axi_arlock({ m00_axi_arlock }), .m_axi_arcache({ m00_axi_arcache }), .m_axi_arprot({ m00_axi_arprot }), .m_axi_arqos({ m00_axi_arqos }), .m_axi_arregion({ m00_axi_arregion }), .m_axi_aruser({ m00_axi_aruser }), .m_axi_arvalid({ m00_axi_arvalid }), .m_axi_arready({ m00_axi_arready }), .m_axi_rid({ m00_axi_rid }), .m_axi_rdata({ m00_axi_rdata }), .m_axi_rresp({ m00_axi_rresp }), .m_axi_rlast({ m00_axi_rlast }), .m_axi_ruser({ m00_axi_ruser }), .m_axi_rvalid({ m00_axi_rvalid }), .m_axi_rready({ m00_axi_rready }) ); endmodule `resetall ================================================ FILE: testbench/axi4_mux/axi_register_rd.v ================================================ /* Copyright (c) 2018 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * AXI4 register (read) */ module axi_register_rd # ( // Width of data bus in bits parameter DATA_WIDTH = 32, // Width of address bus in bits parameter ADDR_WIDTH = 32, // Width of wstrb (width of data bus in words) parameter STRB_WIDTH = (DATA_WIDTH/8), // Width of ID signal parameter ID_WIDTH = 8, // Propagate aruser signal parameter ARUSER_ENABLE = 0, // Width of aruser signal parameter ARUSER_WIDTH = 1, // Propagate ruser signal parameter RUSER_ENABLE = 0, // Width of ruser signal parameter RUSER_WIDTH = 1, // AR channel register type // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter AR_REG_TYPE = 1, // R channel register type // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter R_REG_TYPE = 2 ) ( input wire clk, input wire rst, /* * AXI slave interface */ input wire [ID_WIDTH-1:0] s_axi_arid, input wire [ADDR_WIDTH-1:0] s_axi_araddr, input wire [7:0] s_axi_arlen, input wire [2:0] s_axi_arsize, input wire [1:0] s_axi_arburst, input wire s_axi_arlock, input wire [3:0] s_axi_arcache, input wire [2:0] s_axi_arprot, input wire [3:0] s_axi_arqos, input wire [3:0] s_axi_arregion, input wire [ARUSER_WIDTH-1:0] s_axi_aruser, input wire s_axi_arvalid, output wire s_axi_arready, output wire [ID_WIDTH-1:0] s_axi_rid, output wire [DATA_WIDTH-1:0] s_axi_rdata, output wire [1:0] s_axi_rresp, output wire s_axi_rlast, output wire [RUSER_WIDTH-1:0] s_axi_ruser, output wire s_axi_rvalid, input wire s_axi_rready, /* * AXI master interface */ output wire [ID_WIDTH-1:0] m_axi_arid, output wire [ADDR_WIDTH-1:0] m_axi_araddr, output wire [7:0] m_axi_arlen, output wire [2:0] m_axi_arsize, output wire [1:0] m_axi_arburst, output wire m_axi_arlock, output wire [3:0] m_axi_arcache, output wire [2:0] m_axi_arprot, output wire [3:0] m_axi_arqos, output wire [3:0] m_axi_arregion, output wire [ARUSER_WIDTH-1:0] m_axi_aruser, output wire m_axi_arvalid, input wire m_axi_arready, input wire [ID_WIDTH-1:0] m_axi_rid, input wire [DATA_WIDTH-1:0] m_axi_rdata, input wire [1:0] m_axi_rresp, input wire m_axi_rlast, input wire [RUSER_WIDTH-1:0] m_axi_ruser, input wire m_axi_rvalid, output wire m_axi_rready ); generate // AR channel if (AR_REG_TYPE > 1) begin // skid buffer, no bubble cycles // datapath registers reg s_axi_arready_reg = 1'b0; reg [ID_WIDTH-1:0] m_axi_arid_reg = {ID_WIDTH{1'b0}}; reg [ADDR_WIDTH-1:0] m_axi_araddr_reg = {ADDR_WIDTH{1'b0}}; reg [7:0] m_axi_arlen_reg = 8'd0; reg [2:0] m_axi_arsize_reg = 3'd0; reg [1:0] m_axi_arburst_reg = 2'd0; reg m_axi_arlock_reg = 1'b0; reg [3:0] m_axi_arcache_reg = 4'd0; reg [2:0] m_axi_arprot_reg = 3'd0; reg [3:0] m_axi_arqos_reg = 4'd0; reg [3:0] m_axi_arregion_reg = 4'd0; reg [ARUSER_WIDTH-1:0] m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}}; reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next; reg [ID_WIDTH-1:0] temp_m_axi_arid_reg = {ID_WIDTH{1'b0}}; reg [ADDR_WIDTH-1:0] temp_m_axi_araddr_reg = {ADDR_WIDTH{1'b0}}; reg [7:0] temp_m_axi_arlen_reg = 8'd0; reg [2:0] temp_m_axi_arsize_reg = 3'd0; reg [1:0] temp_m_axi_arburst_reg = 2'd0; reg temp_m_axi_arlock_reg = 1'b0; reg [3:0] temp_m_axi_arcache_reg = 4'd0; reg [2:0] temp_m_axi_arprot_reg = 3'd0; reg [3:0] temp_m_axi_arqos_reg = 4'd0; reg [3:0] temp_m_axi_arregion_reg = 4'd0; reg [ARUSER_WIDTH-1:0] temp_m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}}; reg temp_m_axi_arvalid_reg = 1'b0, temp_m_axi_arvalid_next; // datapath control reg store_axi_ar_input_to_output; reg store_axi_ar_input_to_temp; reg store_axi_ar_temp_to_output; assign s_axi_arready = s_axi_arready_reg; assign m_axi_arid = m_axi_arid_reg; assign m_axi_araddr = m_axi_araddr_reg; assign m_axi_arlen = m_axi_arlen_reg; assign m_axi_arsize = m_axi_arsize_reg; assign m_axi_arburst = m_axi_arburst_reg; assign m_axi_arlock = m_axi_arlock_reg; assign m_axi_arcache = m_axi_arcache_reg; assign m_axi_arprot = m_axi_arprot_reg; assign m_axi_arqos = m_axi_arqos_reg; assign m_axi_arregion = m_axi_arregion_reg; assign m_axi_aruser = ARUSER_ENABLE ? m_axi_aruser_reg : {ARUSER_WIDTH{1'b0}}; assign m_axi_arvalid = m_axi_arvalid_reg; // enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) wire s_axi_arready_early = m_axi_arready | (~temp_m_axi_arvalid_reg & (~m_axi_arvalid_reg | ~s_axi_arvalid)); always @* begin // transfer sink ready state to source m_axi_arvalid_next = m_axi_arvalid_reg; temp_m_axi_arvalid_next = temp_m_axi_arvalid_reg; store_axi_ar_input_to_output = 1'b0; store_axi_ar_input_to_temp = 1'b0; store_axi_ar_temp_to_output = 1'b0; if (s_axi_arready_reg) begin // input is ready if (m_axi_arready | ~m_axi_arvalid_reg) begin // output is ready or currently not valid, transfer data to output m_axi_arvalid_next = s_axi_arvalid; store_axi_ar_input_to_output = 1'b1; end else begin // output is not ready, store input in temp temp_m_axi_arvalid_next = s_axi_arvalid; store_axi_ar_input_to_temp = 1'b1; end end else if (m_axi_arready) begin // input is not ready, but output is ready m_axi_arvalid_next = temp_m_axi_arvalid_reg; temp_m_axi_arvalid_next = 1'b0; store_axi_ar_temp_to_output = 1'b1; end end always @(posedge clk) begin if (rst) begin s_axi_arready_reg <= 1'b0; m_axi_arvalid_reg <= 1'b0; temp_m_axi_arvalid_reg <= 1'b0; end else begin s_axi_arready_reg <= s_axi_arready_early; m_axi_arvalid_reg <= m_axi_arvalid_next; temp_m_axi_arvalid_reg <= temp_m_axi_arvalid_next; end // datapath if (store_axi_ar_input_to_output) begin m_axi_arid_reg <= s_axi_arid; m_axi_araddr_reg <= s_axi_araddr; m_axi_arlen_reg <= s_axi_arlen; m_axi_arsize_reg <= s_axi_arsize; m_axi_arburst_reg <= s_axi_arburst; m_axi_arlock_reg <= s_axi_arlock; m_axi_arcache_reg <= s_axi_arcache; m_axi_arprot_reg <= s_axi_arprot; m_axi_arqos_reg <= s_axi_arqos; m_axi_arregion_reg <= s_axi_arregion; m_axi_aruser_reg <= s_axi_aruser; end else if (store_axi_ar_temp_to_output) begin m_axi_arid_reg <= temp_m_axi_arid_reg; m_axi_araddr_reg <= temp_m_axi_araddr_reg; m_axi_arlen_reg <= temp_m_axi_arlen_reg; m_axi_arsize_reg <= temp_m_axi_arsize_reg; m_axi_arburst_reg <= temp_m_axi_arburst_reg; m_axi_arlock_reg <= temp_m_axi_arlock_reg; m_axi_arcache_reg <= temp_m_axi_arcache_reg; m_axi_arprot_reg <= temp_m_axi_arprot_reg; m_axi_arqos_reg <= temp_m_axi_arqos_reg; m_axi_arregion_reg <= temp_m_axi_arregion_reg; m_axi_aruser_reg <= temp_m_axi_aruser_reg; end if (store_axi_ar_input_to_temp) begin temp_m_axi_arid_reg <= s_axi_arid; temp_m_axi_araddr_reg <= s_axi_araddr; temp_m_axi_arlen_reg <= s_axi_arlen; temp_m_axi_arsize_reg <= s_axi_arsize; temp_m_axi_arburst_reg <= s_axi_arburst; temp_m_axi_arlock_reg <= s_axi_arlock; temp_m_axi_arcache_reg <= s_axi_arcache; temp_m_axi_arprot_reg <= s_axi_arprot; temp_m_axi_arqos_reg <= s_axi_arqos; temp_m_axi_arregion_reg <= s_axi_arregion; temp_m_axi_aruser_reg <= s_axi_aruser; end end end else if (AR_REG_TYPE == 1) begin // simple register, inserts bubble cycles // datapath registers reg s_axi_arready_reg = 1'b0; reg [ID_WIDTH-1:0] m_axi_arid_reg = {ID_WIDTH{1'b0}}; reg [ADDR_WIDTH-1:0] m_axi_araddr_reg = {ADDR_WIDTH{1'b0}}; reg [7:0] m_axi_arlen_reg = 8'd0; reg [2:0] m_axi_arsize_reg = 3'd0; reg [1:0] m_axi_arburst_reg = 2'd0; reg m_axi_arlock_reg = 1'b0; reg [3:0] m_axi_arcache_reg = 4'd0; reg [2:0] m_axi_arprot_reg = 3'd0; reg [3:0] m_axi_arqos_reg = 4'd0; reg [3:0] m_axi_arregion_reg = 4'd0; reg [ARUSER_WIDTH-1:0] m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}}; reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next; // datapath control reg store_axi_ar_input_to_output; assign s_axi_arready = s_axi_arready_reg; assign m_axi_arid = m_axi_arid_reg; assign m_axi_araddr = m_axi_araddr_reg; assign m_axi_arlen = m_axi_arlen_reg; assign m_axi_arsize = m_axi_arsize_reg; assign m_axi_arburst = m_axi_arburst_reg; assign m_axi_arlock = m_axi_arlock_reg; assign m_axi_arcache = m_axi_arcache_reg; assign m_axi_arprot = m_axi_arprot_reg; assign m_axi_arqos = m_axi_arqos_reg; assign m_axi_arregion = m_axi_arregion_reg; assign m_axi_aruser = ARUSER_ENABLE ? m_axi_aruser_reg : {ARUSER_WIDTH{1'b0}}; assign m_axi_arvalid = m_axi_arvalid_reg; // enable ready input next cycle if output buffer will be empty wire s_axi_arready_early = !m_axi_arvalid_next; always @* begin // transfer sink ready state to source m_axi_arvalid_next = m_axi_arvalid_reg; store_axi_ar_input_to_output = 1'b0; if (s_axi_arready_reg) begin m_axi_arvalid_next = s_axi_arvalid; store_axi_ar_input_to_output = 1'b1; end else if (m_axi_arready) begin m_axi_arvalid_next = 1'b0; end end always @(posedge clk) begin if (rst) begin s_axi_arready_reg <= 1'b0; m_axi_arvalid_reg <= 1'b0; end else begin s_axi_arready_reg <= s_axi_arready_early; m_axi_arvalid_reg <= m_axi_arvalid_next; end // datapath if (store_axi_ar_input_to_output) begin m_axi_arid_reg <= s_axi_arid; m_axi_araddr_reg <= s_axi_araddr; m_axi_arlen_reg <= s_axi_arlen; m_axi_arsize_reg <= s_axi_arsize; m_axi_arburst_reg <= s_axi_arburst; m_axi_arlock_reg <= s_axi_arlock; m_axi_arcache_reg <= s_axi_arcache; m_axi_arprot_reg <= s_axi_arprot; m_axi_arqos_reg <= s_axi_arqos; m_axi_arregion_reg <= s_axi_arregion; m_axi_aruser_reg <= s_axi_aruser; end end end else begin // bypass AR channel assign m_axi_arid = s_axi_arid; assign m_axi_araddr = s_axi_araddr; assign m_axi_arlen = s_axi_arlen; assign m_axi_arsize = s_axi_arsize; assign m_axi_arburst = s_axi_arburst; assign m_axi_arlock = s_axi_arlock; assign m_axi_arcache = s_axi_arcache; assign m_axi_arprot = s_axi_arprot; assign m_axi_arqos = s_axi_arqos; assign m_axi_arregion = s_axi_arregion; assign m_axi_aruser = ARUSER_ENABLE ? s_axi_aruser : {ARUSER_WIDTH{1'b0}}; assign m_axi_arvalid = s_axi_arvalid; assign s_axi_arready = m_axi_arready; end // R channel if (R_REG_TYPE > 1) begin // skid buffer, no bubble cycles // datapath registers reg m_axi_rready_reg = 1'b0; reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}; reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}; reg [1:0] s_axi_rresp_reg = 2'b0; reg s_axi_rlast_reg = 1'b0; reg [RUSER_WIDTH-1:0] s_axi_ruser_reg = {RUSER_WIDTH{1'b0}}; reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next; reg [ID_WIDTH-1:0] temp_s_axi_rid_reg = {ID_WIDTH{1'b0}}; reg [DATA_WIDTH-1:0] temp_s_axi_rdata_reg = {DATA_WIDTH{1'b0}}; reg [1:0] temp_s_axi_rresp_reg = 2'b0; reg temp_s_axi_rlast_reg = 1'b0; reg [RUSER_WIDTH-1:0] temp_s_axi_ruser_reg = {RUSER_WIDTH{1'b0}}; reg temp_s_axi_rvalid_reg = 1'b0, temp_s_axi_rvalid_next; // datapath control reg store_axi_r_input_to_output; reg store_axi_r_input_to_temp; reg store_axi_r_temp_to_output; assign m_axi_rready = m_axi_rready_reg; assign s_axi_rid = s_axi_rid_reg; assign s_axi_rdata = s_axi_rdata_reg; assign s_axi_rresp = s_axi_rresp_reg; assign s_axi_rlast = s_axi_rlast_reg; assign s_axi_ruser = RUSER_ENABLE ? s_axi_ruser_reg : {RUSER_WIDTH{1'b0}}; assign s_axi_rvalid = s_axi_rvalid_reg; // enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) wire m_axi_rready_early = s_axi_rready | (~temp_s_axi_rvalid_reg & (~s_axi_rvalid_reg | ~m_axi_rvalid)); always @* begin // transfer sink ready state to source s_axi_rvalid_next = s_axi_rvalid_reg; temp_s_axi_rvalid_next = temp_s_axi_rvalid_reg; store_axi_r_input_to_output = 1'b0; store_axi_r_input_to_temp = 1'b0; store_axi_r_temp_to_output = 1'b0; if (m_axi_rready_reg) begin // input is ready if (s_axi_rready | ~s_axi_rvalid_reg) begin // output is ready or currently not valid, transfer data to output s_axi_rvalid_next = m_axi_rvalid; store_axi_r_input_to_output = 1'b1; end else begin // output is not ready, store input in temp temp_s_axi_rvalid_next = m_axi_rvalid; store_axi_r_input_to_temp = 1'b1; end end else if (s_axi_rready) begin // input is not ready, but output is ready s_axi_rvalid_next = temp_s_axi_rvalid_reg; temp_s_axi_rvalid_next = 1'b0; store_axi_r_temp_to_output = 1'b1; end end always @(posedge clk) begin if (rst) begin m_axi_rready_reg <= 1'b0; s_axi_rvalid_reg <= 1'b0; temp_s_axi_rvalid_reg <= 1'b0; end else begin m_axi_rready_reg <= m_axi_rready_early; s_axi_rvalid_reg <= s_axi_rvalid_next; temp_s_axi_rvalid_reg <= temp_s_axi_rvalid_next; end // datapath if (store_axi_r_input_to_output) begin s_axi_rid_reg <= m_axi_rid; s_axi_rdata_reg <= m_axi_rdata; s_axi_rresp_reg <= m_axi_rresp; s_axi_rlast_reg <= m_axi_rlast; s_axi_ruser_reg <= m_axi_ruser; end else if (store_axi_r_temp_to_output) begin s_axi_rid_reg <= temp_s_axi_rid_reg; s_axi_rdata_reg <= temp_s_axi_rdata_reg; s_axi_rresp_reg <= temp_s_axi_rresp_reg; s_axi_rlast_reg <= temp_s_axi_rlast_reg; s_axi_ruser_reg <= temp_s_axi_ruser_reg; end if (store_axi_r_input_to_temp) begin temp_s_axi_rid_reg <= m_axi_rid; temp_s_axi_rdata_reg <= m_axi_rdata; temp_s_axi_rresp_reg <= m_axi_rresp; temp_s_axi_rlast_reg <= m_axi_rlast; temp_s_axi_ruser_reg <= m_axi_ruser; end end end else if (R_REG_TYPE == 1) begin // simple register, inserts bubble cycles // datapath registers reg m_axi_rready_reg = 1'b0; reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}; reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}; reg [1:0] s_axi_rresp_reg = 2'b0; reg s_axi_rlast_reg = 1'b0; reg [RUSER_WIDTH-1:0] s_axi_ruser_reg = {RUSER_WIDTH{1'b0}}; reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next; // datapath control reg store_axi_r_input_to_output; assign m_axi_rready = m_axi_rready_reg; assign s_axi_rid = s_axi_rid_reg; assign s_axi_rdata = s_axi_rdata_reg; assign s_axi_rresp = s_axi_rresp_reg; assign s_axi_rlast = s_axi_rlast_reg; assign s_axi_ruser = RUSER_ENABLE ? s_axi_ruser_reg : {RUSER_WIDTH{1'b0}}; assign s_axi_rvalid = s_axi_rvalid_reg; // enable ready input next cycle if output buffer will be empty wire m_axi_rready_early = !s_axi_rvalid_next; always @* begin // transfer sink ready state to source s_axi_rvalid_next = s_axi_rvalid_reg; store_axi_r_input_to_output = 1'b0; if (m_axi_rready_reg) begin s_axi_rvalid_next = m_axi_rvalid; store_axi_r_input_to_output = 1'b1; end else if (s_axi_rready) begin s_axi_rvalid_next = 1'b0; end end always @(posedge clk) begin if (rst) begin m_axi_rready_reg <= 1'b0; s_axi_rvalid_reg <= 1'b0; end else begin m_axi_rready_reg <= m_axi_rready_early; s_axi_rvalid_reg <= s_axi_rvalid_next; end // datapath if (store_axi_r_input_to_output) begin s_axi_rid_reg <= m_axi_rid; s_axi_rdata_reg <= m_axi_rdata; s_axi_rresp_reg <= m_axi_rresp; s_axi_rlast_reg <= m_axi_rlast; s_axi_ruser_reg <= m_axi_ruser; end end end else begin // bypass R channel assign s_axi_rid = m_axi_rid; assign s_axi_rdata = m_axi_rdata; assign s_axi_rresp = m_axi_rresp; assign s_axi_rlast = m_axi_rlast; assign s_axi_ruser = RUSER_ENABLE ? m_axi_ruser : {RUSER_WIDTH{1'b0}}; assign s_axi_rvalid = m_axi_rvalid; assign m_axi_rready = s_axi_rready; end endgenerate endmodule `resetall ================================================ FILE: testbench/axi4_mux/axi_register_wr.v ================================================ /* Copyright (c) 2018 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * AXI4 register (write) */ module axi_register_wr # ( // Width of data bus in bits parameter DATA_WIDTH = 32, // Width of address bus in bits parameter ADDR_WIDTH = 32, // Width of wstrb (width of data bus in words) parameter STRB_WIDTH = (DATA_WIDTH/8), // Width of ID signal parameter ID_WIDTH = 8, // Propagate awuser signal parameter AWUSER_ENABLE = 0, // Width of awuser signal parameter AWUSER_WIDTH = 1, // Propagate wuser signal parameter WUSER_ENABLE = 0, // Width of wuser signal parameter WUSER_WIDTH = 1, // Propagate buser signal parameter BUSER_ENABLE = 0, // Width of buser signal parameter BUSER_WIDTH = 1, // AW channel register type // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter AW_REG_TYPE = 1, // W channel register type // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter W_REG_TYPE = 2, // B channel register type // 0 to bypass, 1 for simple buffer, 2 for skid buffer parameter B_REG_TYPE = 1 ) ( input wire clk, input wire rst, /* * AXI slave interface */ input wire [ID_WIDTH-1:0] s_axi_awid, input wire [ADDR_WIDTH-1:0] s_axi_awaddr, input wire [7:0] s_axi_awlen, input wire [2:0] s_axi_awsize, input wire [1:0] s_axi_awburst, input wire s_axi_awlock, input wire [3:0] s_axi_awcache, input wire [2:0] s_axi_awprot, input wire [3:0] s_axi_awqos, input wire [3:0] s_axi_awregion, input wire [AWUSER_WIDTH-1:0] s_axi_awuser, input wire s_axi_awvalid, output wire s_axi_awready, input wire [DATA_WIDTH-1:0] s_axi_wdata, input wire [STRB_WIDTH-1:0] s_axi_wstrb, input wire s_axi_wlast, input wire [WUSER_WIDTH-1:0] s_axi_wuser, input wire s_axi_wvalid, output wire s_axi_wready, output wire [ID_WIDTH-1:0] s_axi_bid, output wire [1:0] s_axi_bresp, output wire [BUSER_WIDTH-1:0] s_axi_buser, output wire s_axi_bvalid, input wire s_axi_bready, /* * AXI master interface */ output wire [ID_WIDTH-1:0] m_axi_awid, output wire [ADDR_WIDTH-1:0] m_axi_awaddr, output wire [7:0] m_axi_awlen, output wire [2:0] m_axi_awsize, output wire [1:0] m_axi_awburst, output wire m_axi_awlock, output wire [3:0] m_axi_awcache, output wire [2:0] m_axi_awprot, output wire [3:0] m_axi_awqos, output wire [3:0] m_axi_awregion, output wire [AWUSER_WIDTH-1:0] m_axi_awuser, output wire m_axi_awvalid, input wire m_axi_awready, output wire [DATA_WIDTH-1:0] m_axi_wdata, output wire [STRB_WIDTH-1:0] m_axi_wstrb, output wire m_axi_wlast, output wire [WUSER_WIDTH-1:0] m_axi_wuser, output wire m_axi_wvalid, input wire m_axi_wready, input wire [ID_WIDTH-1:0] m_axi_bid, input wire [1:0] m_axi_bresp, input wire [BUSER_WIDTH-1:0] m_axi_buser, input wire m_axi_bvalid, output wire m_axi_bready ); generate // AW channel if (AW_REG_TYPE > 1) begin // skid buffer, no bubble cycles // datapath registers reg s_axi_awready_reg = 1'b0; reg [ID_WIDTH-1:0] m_axi_awid_reg = {ID_WIDTH{1'b0}}; reg [ADDR_WIDTH-1:0] m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}}; reg [7:0] m_axi_awlen_reg = 8'd0; reg [2:0] m_axi_awsize_reg = 3'd0; reg [1:0] m_axi_awburst_reg = 2'd0; reg m_axi_awlock_reg = 1'b0; reg [3:0] m_axi_awcache_reg = 4'd0; reg [2:0] m_axi_awprot_reg = 3'd0; reg [3:0] m_axi_awqos_reg = 4'd0; reg [3:0] m_axi_awregion_reg = 4'd0; reg [AWUSER_WIDTH-1:0] m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}}; reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next; reg [ID_WIDTH-1:0] temp_m_axi_awid_reg = {ID_WIDTH{1'b0}}; reg [ADDR_WIDTH-1:0] temp_m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}}; reg [7:0] temp_m_axi_awlen_reg = 8'd0; reg [2:0] temp_m_axi_awsize_reg = 3'd0; reg [1:0] temp_m_axi_awburst_reg = 2'd0; reg temp_m_axi_awlock_reg = 1'b0; reg [3:0] temp_m_axi_awcache_reg = 4'd0; reg [2:0] temp_m_axi_awprot_reg = 3'd0; reg [3:0] temp_m_axi_awqos_reg = 4'd0; reg [3:0] temp_m_axi_awregion_reg = 4'd0; reg [AWUSER_WIDTH-1:0] temp_m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}}; reg temp_m_axi_awvalid_reg = 1'b0, temp_m_axi_awvalid_next; // datapath control reg store_axi_aw_input_to_output; reg store_axi_aw_input_to_temp; reg store_axi_aw_temp_to_output; assign s_axi_awready = s_axi_awready_reg; assign m_axi_awid = m_axi_awid_reg; assign m_axi_awaddr = m_axi_awaddr_reg; assign m_axi_awlen = m_axi_awlen_reg; assign m_axi_awsize = m_axi_awsize_reg; assign m_axi_awburst = m_axi_awburst_reg; assign m_axi_awlock = m_axi_awlock_reg; assign m_axi_awcache = m_axi_awcache_reg; assign m_axi_awprot = m_axi_awprot_reg; assign m_axi_awqos = m_axi_awqos_reg; assign m_axi_awregion = m_axi_awregion_reg; assign m_axi_awuser = AWUSER_ENABLE ? m_axi_awuser_reg : {AWUSER_WIDTH{1'b0}}; assign m_axi_awvalid = m_axi_awvalid_reg; // enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) wire s_axi_awready_early = m_axi_awready | (~temp_m_axi_awvalid_reg & (~m_axi_awvalid_reg | ~s_axi_awvalid)); always @* begin // transfer sink ready state to source m_axi_awvalid_next = m_axi_awvalid_reg; temp_m_axi_awvalid_next = temp_m_axi_awvalid_reg; store_axi_aw_input_to_output = 1'b0; store_axi_aw_input_to_temp = 1'b0; store_axi_aw_temp_to_output = 1'b0; if (s_axi_awready_reg) begin // input is ready if (m_axi_awready | ~m_axi_awvalid_reg) begin // output is ready or currently not valid, transfer data to output m_axi_awvalid_next = s_axi_awvalid; store_axi_aw_input_to_output = 1'b1; end else begin // output is not ready, store input in temp temp_m_axi_awvalid_next = s_axi_awvalid; store_axi_aw_input_to_temp = 1'b1; end end else if (m_axi_awready) begin // input is not ready, but output is ready m_axi_awvalid_next = temp_m_axi_awvalid_reg; temp_m_axi_awvalid_next = 1'b0; store_axi_aw_temp_to_output = 1'b1; end end always @(posedge clk) begin if (rst) begin s_axi_awready_reg <= 1'b0; m_axi_awvalid_reg <= 1'b0; temp_m_axi_awvalid_reg <= 1'b0; end else begin s_axi_awready_reg <= s_axi_awready_early; m_axi_awvalid_reg <= m_axi_awvalid_next; temp_m_axi_awvalid_reg <= temp_m_axi_awvalid_next; end // datapath if (store_axi_aw_input_to_output) begin m_axi_awid_reg <= s_axi_awid; m_axi_awaddr_reg <= s_axi_awaddr; m_axi_awlen_reg <= s_axi_awlen; m_axi_awsize_reg <= s_axi_awsize; m_axi_awburst_reg <= s_axi_awburst; m_axi_awlock_reg <= s_axi_awlock; m_axi_awcache_reg <= s_axi_awcache; m_axi_awprot_reg <= s_axi_awprot; m_axi_awqos_reg <= s_axi_awqos; m_axi_awregion_reg <= s_axi_awregion; m_axi_awuser_reg <= s_axi_awuser; end else if (store_axi_aw_temp_to_output) begin m_axi_awid_reg <= temp_m_axi_awid_reg; m_axi_awaddr_reg <= temp_m_axi_awaddr_reg; m_axi_awlen_reg <= temp_m_axi_awlen_reg; m_axi_awsize_reg <= temp_m_axi_awsize_reg; m_axi_awburst_reg <= temp_m_axi_awburst_reg; m_axi_awlock_reg <= temp_m_axi_awlock_reg; m_axi_awcache_reg <= temp_m_axi_awcache_reg; m_axi_awprot_reg <= temp_m_axi_awprot_reg; m_axi_awqos_reg <= temp_m_axi_awqos_reg; m_axi_awregion_reg <= temp_m_axi_awregion_reg; m_axi_awuser_reg <= temp_m_axi_awuser_reg; end if (store_axi_aw_input_to_temp) begin temp_m_axi_awid_reg <= s_axi_awid; temp_m_axi_awaddr_reg <= s_axi_awaddr; temp_m_axi_awlen_reg <= s_axi_awlen; temp_m_axi_awsize_reg <= s_axi_awsize; temp_m_axi_awburst_reg <= s_axi_awburst; temp_m_axi_awlock_reg <= s_axi_awlock; temp_m_axi_awcache_reg <= s_axi_awcache; temp_m_axi_awprot_reg <= s_axi_awprot; temp_m_axi_awqos_reg <= s_axi_awqos; temp_m_axi_awregion_reg <= s_axi_awregion; temp_m_axi_awuser_reg <= s_axi_awuser; end end end else if (AW_REG_TYPE == 1) begin // simple register, inserts bubble cycles // datapath registers reg s_axi_awready_reg = 1'b0; reg [ID_WIDTH-1:0] m_axi_awid_reg = {ID_WIDTH{1'b0}}; reg [ADDR_WIDTH-1:0] m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}}; reg [7:0] m_axi_awlen_reg = 8'd0; reg [2:0] m_axi_awsize_reg = 3'd0; reg [1:0] m_axi_awburst_reg = 2'd0; reg m_axi_awlock_reg = 1'b0; reg [3:0] m_axi_awcache_reg = 4'd0; reg [2:0] m_axi_awprot_reg = 3'd0; reg [3:0] m_axi_awqos_reg = 4'd0; reg [3:0] m_axi_awregion_reg = 4'd0; reg [AWUSER_WIDTH-1:0] m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}}; reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next; // datapath control reg store_axi_aw_input_to_output; assign s_axi_awready = s_axi_awready_reg; assign m_axi_awid = m_axi_awid_reg; assign m_axi_awaddr = m_axi_awaddr_reg; assign m_axi_awlen = m_axi_awlen_reg; assign m_axi_awsize = m_axi_awsize_reg; assign m_axi_awburst = m_axi_awburst_reg; assign m_axi_awlock = m_axi_awlock_reg; assign m_axi_awcache = m_axi_awcache_reg; assign m_axi_awprot = m_axi_awprot_reg; assign m_axi_awqos = m_axi_awqos_reg; assign m_axi_awregion = m_axi_awregion_reg; assign m_axi_awuser = AWUSER_ENABLE ? m_axi_awuser_reg : {AWUSER_WIDTH{1'b0}}; assign m_axi_awvalid = m_axi_awvalid_reg; // enable ready input next cycle if output buffer will be empty wire s_axi_awready_eawly = !m_axi_awvalid_next; always @* begin // transfer sink ready state to source m_axi_awvalid_next = m_axi_awvalid_reg; store_axi_aw_input_to_output = 1'b0; if (s_axi_awready_reg) begin m_axi_awvalid_next = s_axi_awvalid; store_axi_aw_input_to_output = 1'b1; end else if (m_axi_awready) begin m_axi_awvalid_next = 1'b0; end end always @(posedge clk) begin if (rst) begin s_axi_awready_reg <= 1'b0; m_axi_awvalid_reg <= 1'b0; end else begin s_axi_awready_reg <= s_axi_awready_eawly; m_axi_awvalid_reg <= m_axi_awvalid_next; end // datapath if (store_axi_aw_input_to_output) begin m_axi_awid_reg <= s_axi_awid; m_axi_awaddr_reg <= s_axi_awaddr; m_axi_awlen_reg <= s_axi_awlen; m_axi_awsize_reg <= s_axi_awsize; m_axi_awburst_reg <= s_axi_awburst; m_axi_awlock_reg <= s_axi_awlock; m_axi_awcache_reg <= s_axi_awcache; m_axi_awprot_reg <= s_axi_awprot; m_axi_awqos_reg <= s_axi_awqos; m_axi_awregion_reg <= s_axi_awregion; m_axi_awuser_reg <= s_axi_awuser; end end end else begin // bypass AW channel assign m_axi_awid = s_axi_awid; assign m_axi_awaddr = s_axi_awaddr; assign m_axi_awlen = s_axi_awlen; assign m_axi_awsize = s_axi_awsize; assign m_axi_awburst = s_axi_awburst; assign m_axi_awlock = s_axi_awlock; assign m_axi_awcache = s_axi_awcache; assign m_axi_awprot = s_axi_awprot; assign m_axi_awqos = s_axi_awqos; assign m_axi_awregion = s_axi_awregion; assign m_axi_awuser = AWUSER_ENABLE ? s_axi_awuser : {AWUSER_WIDTH{1'b0}}; assign m_axi_awvalid = s_axi_awvalid; assign s_axi_awready = m_axi_awready; end // W channel if (W_REG_TYPE > 1) begin // skid buffer, no bubble cycles // datapath registers reg s_axi_wready_reg = 1'b0; reg [DATA_WIDTH-1:0] m_axi_wdata_reg = {DATA_WIDTH{1'b0}}; reg [STRB_WIDTH-1:0] m_axi_wstrb_reg = {STRB_WIDTH{1'b0}}; reg m_axi_wlast_reg = 1'b0; reg [WUSER_WIDTH-1:0] m_axi_wuser_reg = {WUSER_WIDTH{1'b0}}; reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next; reg [DATA_WIDTH-1:0] temp_m_axi_wdata_reg = {DATA_WIDTH{1'b0}}; reg [STRB_WIDTH-1:0] temp_m_axi_wstrb_reg = {STRB_WIDTH{1'b0}}; reg temp_m_axi_wlast_reg = 1'b0; reg [WUSER_WIDTH-1:0] temp_m_axi_wuser_reg = {WUSER_WIDTH{1'b0}}; reg temp_m_axi_wvalid_reg = 1'b0, temp_m_axi_wvalid_next; // datapath control reg store_axi_w_input_to_output; reg store_axi_w_input_to_temp; reg store_axi_w_temp_to_output; assign s_axi_wready = s_axi_wready_reg; assign m_axi_wdata = m_axi_wdata_reg; assign m_axi_wstrb = m_axi_wstrb_reg; assign m_axi_wlast = m_axi_wlast_reg; assign m_axi_wuser = WUSER_ENABLE ? m_axi_wuser_reg : {WUSER_WIDTH{1'b0}}; assign m_axi_wvalid = m_axi_wvalid_reg; // enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) wire s_axi_wready_early = m_axi_wready | (~temp_m_axi_wvalid_reg & (~m_axi_wvalid_reg | ~s_axi_wvalid)); always @* begin // transfer sink ready state to source m_axi_wvalid_next = m_axi_wvalid_reg; temp_m_axi_wvalid_next = temp_m_axi_wvalid_reg; store_axi_w_input_to_output = 1'b0; store_axi_w_input_to_temp = 1'b0; store_axi_w_temp_to_output = 1'b0; if (s_axi_wready_reg) begin // input is ready if (m_axi_wready | ~m_axi_wvalid_reg) begin // output is ready or currently not valid, transfer data to output m_axi_wvalid_next = s_axi_wvalid; store_axi_w_input_to_output = 1'b1; end else begin // output is not ready, store input in temp temp_m_axi_wvalid_next = s_axi_wvalid; store_axi_w_input_to_temp = 1'b1; end end else if (m_axi_wready) begin // input is not ready, but output is ready m_axi_wvalid_next = temp_m_axi_wvalid_reg; temp_m_axi_wvalid_next = 1'b0; store_axi_w_temp_to_output = 1'b1; end end always @(posedge clk) begin if (rst) begin s_axi_wready_reg <= 1'b0; m_axi_wvalid_reg <= 1'b0; temp_m_axi_wvalid_reg <= 1'b0; end else begin s_axi_wready_reg <= s_axi_wready_early; m_axi_wvalid_reg <= m_axi_wvalid_next; temp_m_axi_wvalid_reg <= temp_m_axi_wvalid_next; end // datapath if (store_axi_w_input_to_output) begin m_axi_wdata_reg <= s_axi_wdata; m_axi_wstrb_reg <= s_axi_wstrb; m_axi_wlast_reg <= s_axi_wlast; m_axi_wuser_reg <= s_axi_wuser; end else if (store_axi_w_temp_to_output) begin m_axi_wdata_reg <= temp_m_axi_wdata_reg; m_axi_wstrb_reg <= temp_m_axi_wstrb_reg; m_axi_wlast_reg <= temp_m_axi_wlast_reg; m_axi_wuser_reg <= temp_m_axi_wuser_reg; end if (store_axi_w_input_to_temp) begin temp_m_axi_wdata_reg <= s_axi_wdata; temp_m_axi_wstrb_reg <= s_axi_wstrb; temp_m_axi_wlast_reg <= s_axi_wlast; temp_m_axi_wuser_reg <= s_axi_wuser; end end end else if (W_REG_TYPE == 1) begin // simple register, inserts bubble cycles // datapath registers reg s_axi_wready_reg = 1'b0; reg [DATA_WIDTH-1:0] m_axi_wdata_reg = {DATA_WIDTH{1'b0}}; reg [STRB_WIDTH-1:0] m_axi_wstrb_reg = {STRB_WIDTH{1'b0}}; reg m_axi_wlast_reg = 1'b0; reg [WUSER_WIDTH-1:0] m_axi_wuser_reg = {WUSER_WIDTH{1'b0}}; reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next; // datapath control reg store_axi_w_input_to_output; assign s_axi_wready = s_axi_wready_reg; assign m_axi_wdata = m_axi_wdata_reg; assign m_axi_wstrb = m_axi_wstrb_reg; assign m_axi_wlast = m_axi_wlast_reg; assign m_axi_wuser = WUSER_ENABLE ? m_axi_wuser_reg : {WUSER_WIDTH{1'b0}}; assign m_axi_wvalid = m_axi_wvalid_reg; // enable ready input next cycle if output buffer will be empty wire s_axi_wready_ewly = !m_axi_wvalid_next; always @* begin // transfer sink ready state to source m_axi_wvalid_next = m_axi_wvalid_reg; store_axi_w_input_to_output = 1'b0; if (s_axi_wready_reg) begin m_axi_wvalid_next = s_axi_wvalid; store_axi_w_input_to_output = 1'b1; end else if (m_axi_wready) begin m_axi_wvalid_next = 1'b0; end end always @(posedge clk) begin if (rst) begin s_axi_wready_reg <= 1'b0; m_axi_wvalid_reg <= 1'b0; end else begin s_axi_wready_reg <= s_axi_wready_ewly; m_axi_wvalid_reg <= m_axi_wvalid_next; end // datapath if (store_axi_w_input_to_output) begin m_axi_wdata_reg <= s_axi_wdata; m_axi_wstrb_reg <= s_axi_wstrb; m_axi_wlast_reg <= s_axi_wlast; m_axi_wuser_reg <= s_axi_wuser; end end end else begin // bypass W channel assign m_axi_wdata = s_axi_wdata; assign m_axi_wstrb = s_axi_wstrb; assign m_axi_wlast = s_axi_wlast; assign m_axi_wuser = WUSER_ENABLE ? s_axi_wuser : {WUSER_WIDTH{1'b0}}; assign m_axi_wvalid = s_axi_wvalid; assign s_axi_wready = m_axi_wready; end // B channel if (B_REG_TYPE > 1) begin // skid buffer, no bubble cycles // datapath registers reg m_axi_bready_reg = 1'b0; reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}; reg [1:0] s_axi_bresp_reg = 2'b0; reg [BUSER_WIDTH-1:0] s_axi_buser_reg = {BUSER_WIDTH{1'b0}}; reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next; reg [ID_WIDTH-1:0] temp_s_axi_bid_reg = {ID_WIDTH{1'b0}}; reg [1:0] temp_s_axi_bresp_reg = 2'b0; reg [BUSER_WIDTH-1:0] temp_s_axi_buser_reg = {BUSER_WIDTH{1'b0}}; reg temp_s_axi_bvalid_reg = 1'b0, temp_s_axi_bvalid_next; // datapath control reg store_axi_b_input_to_output; reg store_axi_b_input_to_temp; reg store_axi_b_temp_to_output; assign m_axi_bready = m_axi_bready_reg; assign s_axi_bid = s_axi_bid_reg; assign s_axi_bresp = s_axi_bresp_reg; assign s_axi_buser = BUSER_ENABLE ? s_axi_buser_reg : {BUSER_WIDTH{1'b0}}; assign s_axi_bvalid = s_axi_bvalid_reg; // enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) wire m_axi_bready_early = s_axi_bready | (~temp_s_axi_bvalid_reg & (~s_axi_bvalid_reg | ~m_axi_bvalid)); always @* begin // transfer sink ready state to source s_axi_bvalid_next = s_axi_bvalid_reg; temp_s_axi_bvalid_next = temp_s_axi_bvalid_reg; store_axi_b_input_to_output = 1'b0; store_axi_b_input_to_temp = 1'b0; store_axi_b_temp_to_output = 1'b0; if (m_axi_bready_reg) begin // input is ready if (s_axi_bready | ~s_axi_bvalid_reg) begin // output is ready or currently not valid, transfer data to output s_axi_bvalid_next = m_axi_bvalid; store_axi_b_input_to_output = 1'b1; end else begin // output is not ready, store input in temp temp_s_axi_bvalid_next = m_axi_bvalid; store_axi_b_input_to_temp = 1'b1; end end else if (s_axi_bready) begin // input is not ready, but output is ready s_axi_bvalid_next = temp_s_axi_bvalid_reg; temp_s_axi_bvalid_next = 1'b0; store_axi_b_temp_to_output = 1'b1; end end always @(posedge clk) begin if (rst) begin m_axi_bready_reg <= 1'b0; s_axi_bvalid_reg <= 1'b0; temp_s_axi_bvalid_reg <= 1'b0; end else begin m_axi_bready_reg <= m_axi_bready_early; s_axi_bvalid_reg <= s_axi_bvalid_next; temp_s_axi_bvalid_reg <= temp_s_axi_bvalid_next; end // datapath if (store_axi_b_input_to_output) begin s_axi_bid_reg <= m_axi_bid; s_axi_bresp_reg <= m_axi_bresp; s_axi_buser_reg <= m_axi_buser; end else if (store_axi_b_temp_to_output) begin s_axi_bid_reg <= temp_s_axi_bid_reg; s_axi_bresp_reg <= temp_s_axi_bresp_reg; s_axi_buser_reg <= temp_s_axi_buser_reg; end if (store_axi_b_input_to_temp) begin temp_s_axi_bid_reg <= m_axi_bid; temp_s_axi_bresp_reg <= m_axi_bresp; temp_s_axi_buser_reg <= m_axi_buser; end end end else if (B_REG_TYPE == 1) begin // simple register, inserts bubble cycles // datapath registers reg m_axi_bready_reg = 1'b0; reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}; reg [1:0] s_axi_bresp_reg = 2'b0; reg [BUSER_WIDTH-1:0] s_axi_buser_reg = {BUSER_WIDTH{1'b0}}; reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next; // datapath control reg store_axi_b_input_to_output; assign m_axi_bready = m_axi_bready_reg; assign s_axi_bid = s_axi_bid_reg; assign s_axi_bresp = s_axi_bresp_reg; assign s_axi_buser = BUSER_ENABLE ? s_axi_buser_reg : {BUSER_WIDTH{1'b0}}; assign s_axi_bvalid = s_axi_bvalid_reg; // enable ready input next cycle if output buffer will be empty wire m_axi_bready_early = !s_axi_bvalid_next; always @* begin // transfer sink ready state to source s_axi_bvalid_next = s_axi_bvalid_reg; store_axi_b_input_to_output = 1'b0; if (m_axi_bready_reg) begin s_axi_bvalid_next = m_axi_bvalid; store_axi_b_input_to_output = 1'b1; end else if (s_axi_bready) begin s_axi_bvalid_next = 1'b0; end end always @(posedge clk) begin if (rst) begin m_axi_bready_reg <= 1'b0; s_axi_bvalid_reg <= 1'b0; end else begin m_axi_bready_reg <= m_axi_bready_early; s_axi_bvalid_reg <= s_axi_bvalid_next; end // datapath if (store_axi_b_input_to_output) begin s_axi_bid_reg <= m_axi_bid; s_axi_bresp_reg <= m_axi_bresp; s_axi_buser_reg <= m_axi_buser; end end end else begin // bypass B channel assign s_axi_bid = m_axi_bid; assign s_axi_bresp = m_axi_bresp; assign s_axi_buser = BUSER_ENABLE ? m_axi_buser : {BUSER_WIDTH{1'b0}}; assign s_axi_bvalid = m_axi_bvalid; assign m_axi_bready = s_axi_bready; end endgenerate endmodule `resetall ================================================ FILE: testbench/axi4_mux/priority_encoder.v ================================================ /* Copyright (c) 2014-2021 Alex Forencich Copyright 2024 Antmicro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ // Language: Verilog 2001 `resetall `default_nettype none /* * Priority encoder module */ module priority_encoder # ( parameter WIDTH = 4, // LSB priority selection parameter LSB_HIGH_PRIORITY = 0 ) ( input wire [WIDTH-1:0] input_unencoded, output wire output_valid, output wire [$clog2(WIDTH)-1:0] output_encoded, output wire [WIDTH-1:0] output_unencoded ); parameter LEVELS = WIDTH > 2 ? $clog2(WIDTH) : 1; parameter W = 2**LEVELS; // pad input to even power of two wire [W-1:0] input_padded = {{W-WIDTH{1'b0}}, input_unencoded}; wire [W/2-1:0] stage_valid[LEVELS-1:0]; wire [W/2-1:0] stage_enc[LEVELS-1:0]; generate genvar l, n; // process input bits; generate valid bit and encoded bit for each pair for (n = 0; n < W/2; n = n + 1) begin : loop_in assign stage_valid[0][n] = |input_padded[n*2+1:n*2]; if (LSB_HIGH_PRIORITY) begin // bit 0 is highest priority assign stage_enc[0][n] = !input_padded[n*2+0]; end else begin // bit 0 is lowest priority assign stage_enc[0][n] = input_padded[n*2+1]; end end // compress down to single valid bit and encoded bus for (l = 1; l < LEVELS; l = l + 1) begin : loop_levels for (n = 0; n < W/(2*2**l); n = n + 1) begin : loop_compress assign stage_valid[l][n] = |stage_valid[l-1][n*2+1:n*2]; if (LSB_HIGH_PRIORITY) begin // bit 0 is highest priority assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+0] ? {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]} : {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]}; end else begin // bit 0 is lowest priority assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+1] ? {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]} : {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]}; end end end endgenerate assign output_valid = stage_valid[LEVELS-1]; assign output_encoded = stage_enc[LEVELS-1]; assign output_unencoded = 1 << output_encoded; endmodule `resetall ================================================ FILE: testbench/axi_lsu_dma_bridge.sv ================================================ // connects LSI master to external AXI slave and DMA slave module axi_lsu_dma_bridge #( parameter M_ID_WIDTH = 8, parameter S0_ID_WIDTH = 8 ) ( input clk, input reset_l, // master read bus input m_arvalid, input [M_ID_WIDTH-1:0] m_arid, input[31:0] m_araddr, output m_arready, output m_rvalid, input m_rready, output [63:0] m_rdata, output [M_ID_WIDTH-1:0] m_rid, output [1:0] m_rresp, output m_rlast, // master write bus input m_awvalid, input [M_ID_WIDTH-1:0] m_awid, input[31:0] m_awaddr, output m_awready, input m_wvalid, output m_wready, output[1:0] m_bresp, output m_bvalid, output[M_ID_WIDTH-1:0] m_bid, input m_bready, // slave 0 if general ext memory output s0_arvalid, input s0_arready, input s0_rvalid, input[S0_ID_WIDTH-1:0] s0_rid, input[1:0] s0_rresp, input[63:0] s0_rdata, input s0_rlast, output s0_rready, output s0_awvalid, input s0_awready, output s0_wvalid, input s0_wready, input[1:0] s0_bresp, input s0_bvalid, input[S0_ID_WIDTH-1:0] s0_bid, output s0_bready, // slave 1 if DMA port output s1_arvalid, input s1_arready, input s1_rvalid, input[1:0] s1_rresp, input[63:0] s1_rdata, input s1_rlast, output s1_rready, output s1_awvalid, input s1_awready, output s1_wvalid, input s1_wready, input[1:0] s1_bresp, input s1_bvalid, output s1_bready ); parameter ICCM_BASE = `RV_ICCM_BITS; // in LSBs localparam IDFIFOSZ = $clog2(`RV_DMA_BUF_DEPTH); bit[31:0] iccm_real_base_addr = `RV_ICCM_SADR ; wire ar_slave_select; wire aw_slave_select; wire w_slave_select; wire rresp_select; wire bresp_select; wire ar_iccm_select; wire aw_iccm_select; reg [1:0] wsel_iptr, wsel_optr; reg [2:0] wsel_count; reg [3:0] wsel; reg [M_ID_WIDTH-1:0] arid [1< // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 #include "jtagdpi.h" #include #include #include #include #include #include "tcp_server.h" // Uncomment to enable JTAG DPI debugging. The code will print vertically // oriented waveform for all JTAG signals. //#define JTAGDPI_DEBUG struct jtagdpi_signals { uint8_t tck; uint8_t tms; uint8_t tdi; uint8_t tdo; uint8_t trst_n; uint8_t srst_n; }; struct jtagdpi_ctx { // Server context struct tcp_server_ctx *sock; // Signals struct jtagdpi_signals curr; #ifdef JTAGDPI_DEBUG struct jtagdpi_signals prev; uint8_t init; #endif }; /** * Reset the JTAG signals to a "dongle unplugged" state */ static void reset_jtag_signals(struct jtagdpi_ctx *ctx) { assert(ctx); // Set all to zero memset(&ctx->curr, 0, sizeof(struct jtagdpi_signals)); #ifdef JTAGDPI_DEBUG memset(&ctx->prev, 0, sizeof(struct jtagdpi_signals)); #endif // trst_n is pulled down (reset active) by default // srst_n is pulled up (reset not active) by default ctx->curr.srst_n = 1; #ifdef JTAGDPI_DEBUG ctx->prev.srst_n = 1; #endif } /** * Update the JTAG signals in the context structure */ static void update_jtag_signals(struct jtagdpi_ctx *ctx) { assert(ctx); /* * Documentation pointer: * The remote_bitbang protocol implemented below is documented in the OpenOCD * source tree at doc/manual/jtag/drivers/remote_bitbang.txt, or online at * https://repo.or.cz/openocd.git/blob/HEAD:/doc/manual/jtag/drivers/remote_bitbang.txt */ // read a command byte char cmd; if (!tcp_server_read(ctx->sock, &cmd)) { return; } bool act_send_resp = false; bool act_quit = false; // parse received command byte if (cmd >= '0' && cmd <= '7') { // JTAG write char cmd_bit = cmd - '0'; ctx->curr.tdi = (cmd_bit >> 0) & 0x1; ctx->curr.tms = (cmd_bit >> 1) & 0x1; ctx->curr.tck = (cmd_bit >> 2) & 0x1; } else if (cmd >= 'r' && cmd <= 'u') { // JTAG reset (active high from OpenOCD) char cmd_bit = cmd - 'r'; ctx->curr.srst_n = !((cmd_bit >> 0) & 0x1); ctx->curr.trst_n = !((cmd_bit >> 1) & 0x1); } else if (cmd == 'R') { // JTAG read act_send_resp = true; } else if (cmd == 'B') { // printf("%s: BLINK ON!\n", ctx->display_name); } else if (cmd == 'b') { // printf("%s: BLINK OFF!\n", ctx->display_name); } else if (cmd == 'Q') { // quit (client disconnect) act_quit = true; } else { fprintf(stderr, "JTAG DPI Protocol violation detected: unsupported command %c\n", cmd); exit(1); } // send tdo as response if (act_send_resp) { char tdo_ascii = ctx->curr.tdo + '0'; tcp_server_write(ctx->sock, tdo_ascii); } if (act_quit) { printf("JTAG DPI: Remote disconnected.\n"); tcp_server_client_close(ctx->sock); } } void *jtagdpi_create(const char *display_name, int listen_port) { struct jtagdpi_ctx *ctx = (struct jtagdpi_ctx *)calloc(1, sizeof(struct jtagdpi_ctx)); assert(ctx); // Create socket ctx->sock = tcp_server_create(display_name, listen_port); #ifdef JTAGDPI_DEBUG ctx->init = 1; #endif reset_jtag_signals(ctx); printf( "\n" "JTAG: Virtual JTAG interface %s is listening on port %d. Use\n" "OpenOCD and the following configuration to connect:\n" " interface remote_bitbang\n" " remote_bitbang_host localhost\n" " remote_bitbang_port %d\n", display_name, listen_port, listen_port); return (void *)ctx; } void jtagdpi_close(void *ctx_void) { struct jtagdpi_ctx *ctx = (struct jtagdpi_ctx *)ctx_void; if (!ctx) { return; } tcp_server_close(ctx->sock); free(ctx); } #ifdef JTAGDPI_DEBUG static void jtagdpi_dbg(struct jtagdpi_ctx *ctx) { uint8_t* curr = (uint8_t*)&ctx->curr; uint8_t* prev = (uint8_t*)&ctx->prev; if (ctx->init) { fprintf(stderr, "tck tms tdi tdo trst srst\n"); ctx->init = 0; } for (int i=0; i<6; ++i) { if (!prev[i] && curr[i]) { fprintf(stderr, "\\ "); } if ( prev[i] && curr[i]) { fprintf(stderr, " | "); } if ( prev[i] && !curr[i]) { fprintf(stderr, "/ "); } if (!prev[i] && !curr[i]) { fprintf(stderr, "| "); } } fprintf(stderr, "\n"); } #endif void jtagdpi_tick(void *ctx_void, svBit *tck, svBit *tms, svBit *tdi, svBit *trst_n, svBit *srst_n, const svBit tdo) { struct jtagdpi_ctx *ctx = (struct jtagdpi_ctx *)ctx_void; // Get TDO ctx->curr.tdo = tdo; // TODO: Evaluate moving this functionality into a separate thread if (ctx) { update_jtag_signals(ctx); } #ifdef JTAGDPI_DEBUG if (memcmp(&ctx->curr, &ctx->prev, sizeof(struct jtagdpi_signals))) { jtagdpi_dbg(ctx); memcpy(&ctx->prev, &ctx->curr, sizeof(struct jtagdpi_signals)); } #endif *tdi = ctx->curr.tdi; *tms = ctx->curr.tms; *tck = ctx->curr.tck; *srst_n = ctx->curr.srst_n; *trst_n = ctx->curr.trst_n; } ================================================ FILE: testbench/jtagdpi/jtagdpi.h ================================================ // Copyright lowRISC contributors. // Copyright 2024 Antmicro // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 #ifndef OPENTITAN_HW_DV_DPI_JTAGDPI_JTAGDPI_H_ #define OPENTITAN_HW_DV_DPI_JTAGDPI_JTAGDPI_H_ #include #ifdef __cplusplus extern "C" { #endif struct jtagdpi_ctx; /** * Constructor: Create and initialize jtagdpi context object * * Call from a initial block. * * @param display_name Name of the JTAG interface (for display purposes only) * @param listen_port Port to listen on * @return an initialized struct jtagdpi_ctx context object */ void *jtagdpi_create(const char *display_name, int listen_port); /** * Destructor: Close all connections and free all resources * * Call from a finish block. * * @param ctx_void a struct jtagdpi_ctx context object */ void jtagdpi_close(void *ctx_void); /** * Drive JTAG signals * * Call this function from the simulation at every clock tick to read/write * from/to the JTAG signals. * * @param ctx_void a struct jtagdpi_ctx context object * @param tck JTAG test clock signal * @param tms JTAG test mode select signal * @param tdi JTAG test data input signal * @param trst_n JTAG test reset signal (active low) * @param srst_n JTAG system reset signal (active low) * @param tdo JTAG test data out */ void jtagdpi_tick(void *ctx_void, svBit *tck, svBit *tms, svBit *tdi, svBit *trst_n, svBit *srst_n, const svBit tdo); #ifdef __cplusplus } // extern "C" #endif #endif // OPENTITAN_HW_DV_DPI_JTAGDPI_JTAGDPI_H_ ================================================ FILE: testbench/jtagdpi/jtagdpi.sv ================================================ // Copyright lowRISC contributors. // Copyright 2024 Antmicro // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 module jtagdpi #( parameter string Name = "jtag0", // name of the JTAG interface (display only) parameter int ListenPort = 44853 // TCP port to listen on )( input logic clk_i, input logic rst_ni, output logic jtag_tck, output logic jtag_tms, output logic jtag_tdi, input logic jtag_tdo, output logic jtag_trst_n, output logic jtag_srst_n ); import "DPI-C" function chandle jtagdpi_create(input string name, input int listen_port); import "DPI-C" function void jtagdpi_tick(input chandle ctx, output bit tck, output bit tms, output bit tdi, output bit trst_n, output bit srst_n, input bit tdo); import "DPI-C" function void jtagdpi_close(input chandle ctx); chandle ctx; initial begin ctx = jtagdpi_create(Name, ListenPort); end final begin jtagdpi_close(ctx); ctx = null; end always_ff @(posedge clk_i, negedge rst_ni) begin jtagdpi_tick(ctx, jtag_tck, jtag_tms, jtag_tdi, jtag_trst_n, jtag_srst_n, jtag_tdo); end endmodule ================================================ FILE: testbench/link.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0; .text : { *(.text*) } _end = .; . = 0x10000; .data : ALIGN(0x800) { *(.*data) *(.rodata*) STACK = ALIGN(16) + 0x8000; } } ================================================ FILE: testbench/openocd_scripts/common.tcl ================================================ # SPDX-License-Identifier: Apache-2.0 # Copyright 2024 Antmicro # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # proc compare {x y} { puts "'$x' vs. '$y'" if {[llength $y] != [llength $y]} { puts "length mismatch!" return -1 } for {set i 0} {$i < [llength $x]} {incr i} { if {[lindex $x $i] != [lindex $y $i]} { puts "item $i mismatch!" return -1 } } return 0 } set STDOUT 0x300300cc set dmstatus_addr 0x11 ================================================ FILE: testbench/openocd_scripts/jtag_cg.tcl ================================================ # SPDX-License-Identifier: Apache-2.0 # Copyright 2024 Antmicro # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # proc dmi_dump {} { # Dumps all DMI registers defined by the spec # DMI regs per "RISC-V External Debug Support Version 0.13.2" set dmi_regs { {0x04 "data0"} {0x0f "data1"} {0x10 "dmcontrol"} {0x11 "dmstatus"} {0x12 "hartinfo"} {0x13 "haltsum1"} {0x14 "hawindowsel"} {0x15 "hawindow"} {0x16 "abstractcs"} {0x17 "command"} {0x18 "abstractauto"} {0x19 "configstrptr0"} {0x1a "configstrptr1"} {0x1b "configstrptr2"} {0x1c "configstrptr3"} {0x1d "nextdm"} {0x20 "progbuf0"} {0x2f "progbuf15"} {0x30 "authdata"} {0x34 "haltsum2"} {0x35 "haltsum3"} {0x37 "sbaddress3"} {0x38 "sbcs"} {0x39 "sbaddress0"} {0x3a "sbaddress1"} {0x3b "sbaddress2"} {0x3c "sbdata0"} {0x3d "sbdata1"} {0x3e "sbdata2"} {0x3f "sbdata3"} {0x40 "haltsum"} } puts "Dumping DMI registers" foreach it $dmi_regs { set addr [lindex $it 0] set name [lindex $it 1] set val [riscv dmi_read $addr] puts " $addr $name $val" } } proc test_single_access { addr size data1 data2 } { # Tests memory access to a single address. Writes data1, then overwrites # it with data2, performs readback and compares the read value. set astr [format %08X $addr] puts " $size-bit access to 0x$astr" # Write 1 if {[catch { write_memory $addr $size $data1 phys }]} { return -1 } # Write 2 if {[catch { write_memory $addr $size $data2 phys }]} { return -1 } # Read if {[catch { set readback [read_memory $addr $size 1 phys] }]} { return -1 } # Compare if {[compare $readback $data2] != 0} { return -1 } return 0 } proc test_memory_access { access_mode base_address widths uwidths } { # Test various types of memory access to the given address # "widths" is a list of aligned access sizes to execute and "uwidths" # is a list of unaligned accesses to perform. puts "Testing memory access at $base_address using $access_mode mode" riscv set_mem_access $access_mode set addr0 $base_address set addr1 [ expr {$base_address + 1} ] set addr2 [ expr {$base_address + 2} ] set addr3 [ expr {$base_address + 3} ] set data32_1 0xCAFEBACA set data32_2 0xDEADBEEF set data16_1 0xFACE set data16_2 0x5A5A set data8_1 0x55 set data8_2 0xAA # Aligned accesses puts " testing aligned access" if {[lsearch -exact $widths 32] >= 0} { test_single_access $addr0 32 $data32_1 $data32_2 } if {[lsearch -exact $widths 16] >= 0} { test_single_access $addr0 16 $data16_1 $data16_2 test_single_access $addr2 16 $data16_2 $data16_1 } if {[lsearch -exact $widths 8] >= 0} { test_single_access $addr0 8 $data8_1 $data8_2 test_single_access $addr1 8 $data8_2 $data8_1 test_single_access $addr2 8 $data8_1 $data8_2 test_single_access $addr3 8 $data8_2 $data8_1 } # Unaligned accesses puts " testing unaligned access" if {[lsearch -exact $uwidths 32] >= 0} { test_single_access $addr1 32 $data32_2 $data32_1 test_single_access $addr2 32 $data32_1 $data32_2 test_single_access $addr3 32 $data32_2 $data32_1 } if {[lsearch -exact $uwidths 16] >= 0} { test_single_access $addr1 16 $data16_2 $data16_1 test_single_access $addr3 16 $data16_2 $data16_1 } } # Memory region base addesses for "default" VeeR configuration set ram_begin 0x00000000 set dccm_begin 0xF0040000 set iccm_begin 0xEE000000 set pic_begin 0xF00C0000 init set script_dir [file dirname [info script]] source [file join $script_dir common.tcl] puts "Read Debug Module Status Register..." set val [riscv dmi_read $dmstatus_addr] puts " dmstatus: $val" if {($val & 0x00000c00) == 0} { echo "The hart is halted!" shutdown error } puts "" # Dump all DMI registers dmi_dump # Access abstractauto (0x18) DMI register puts "Exercising abstractauto (0x18) DMI register" for {set i 0} {$i < 10} {incr i} { riscv dmi_write 0x18 [expr {int(rand()*0xFFFFFFFF)}] riscv dmi_read 0x18 riscv dmi_write 0x18 0 } # Access sbdata1 (0x3D) for {set i 0} {$i < 10} {incr i} { riscv dmi_write 0x3D [expr {int(rand()*0xFFFFFFFF)}] riscv dmi_read 0x3D riscv dmi_write 0x3D 0 } # Test access in sysbus mode for {set i 0} {$i < 5} {incr i} { test_memory_access "sysbus" $dccm_begin {32 16 8} {32 16} test_memory_access "sysbus" $ram_begin {32 16 8} {32 16} test_memory_access "sysbus" $iccm_begin {32} {32 16} test_memory_access "sysbus" $pic_begin {32 16 8} {32 16} } # Halt the core puts "Halting the core" halt set val [riscv dmi_read $dmstatus_addr] puts " dmstatus: $val" # Manually attempt 64-bit sysbus transaction to trigger internal illegal size # error in the debug core puts "Attempting 64-bit memory access in abstract mode" for {set i 0} {$i < 5} {incr i} { riscv dmi_write 0x38 0x000E0000 riscv dmi_write 0x39 $ram_begin riscv dmi_write 0x3C [expr {int(rand()*0xFFFFFFFF)}] # Clear errors riscv dmi_write 0x38 0x00407000 } puts "Testing automatic bus read (sbreadonaddr=1)" for {set i 0} {$i < 5} {incr i} { riscv dmi_write 0x38 0x00140000 for {set j 0} {$j < 5} {incr j} { riscv dmi_write 0x39 [expr {$ram_begin + 4 * $j}] set val [riscv dmi_read 0x3C] puts " sbdata0: $val" } } puts "Testing automatic bus read and address increment (sbreadondata=1, sbautoincrement=1)" for {set i 0} {$i < 5} {incr i} { riscv dmi_write 0x38 0x00058000 riscv dmi_write 0x39 $ram_begin for {set j 0} {$j < 5} {incr j} { set val [riscv dmi_read 0x3C] puts " sbdata0: $val" } } # Test access in abstract mode for {set i 0} {$i < 5} {incr i} { test_memory_access "abstract" $dccm_begin {32 16 8} {32 16} test_memory_access "abstract" $ram_begin {32 16 8} {32 16} test_memory_access "abstract" $iccm_begin {32} {32 16} # No abstract access to PIC #test_memory_access "abstract" $pic_begin {32} {} } # Send signal to call $finish riscv set_mem_access sysbus write_memory 0xd0580000 8 0xFF phys shutdown ================================================ FILE: testbench/openocd_scripts/sim-jtagdpi.cfg ================================================ # Copyright lowRISC contributors. # Copyright 2024 Antmicro # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 # "JTAG adapter" for simulation, exposed to OpenOCD through a TCP socket # speaking the remote_bitbang protocol. The adapter is implemented as # SystemVerilog DPI module. adapter driver remote_bitbang remote_bitbang port 5000 remote_bitbang host localhost ================================================ FILE: testbench/openocd_scripts/veer-el2-rst.cfg ================================================ set _CHIPNAME riscv jtag newtap $_CHIPNAME tap -irlen 5 set _TARGETNAME $_CHIPNAME.tap target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME -rtos hwthread # Mem access mode riscv set_mem_access sysbus # The following commands disable target examination and set explicitly the # core parameters read from CSRs. These required a modified version of # OpenOCD from https://github.com/antmicro/openocd/tree/riscv-nohalt riscv set_nohalt on riscv set_xlen 32 riscv set_misa 0x40001104 ================================================ FILE: testbench/openocd_scripts/verilator-rst.cfg ================================================ source [find sim-jtagdpi.cfg] source [find veer-el2-rst.cfg] ================================================ FILE: testbench/tb_top.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2019 Western Digital Corporation or its affiliates. // Copyright (c) 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // `ifndef VERILATOR module tb_top import tb_top_pkg::*; #( parameter int MAX_CYCLES = 2_000_000, `include "el2_param.vh" ); logic i_cpu_halt_req, o_cpu_halt_ack, o_cpu_halt_status; logic i_cpu_run_req, o_cpu_run_ack; logic mpc_debug_halt_req, mpc_debug_halt_ack; logic mpc_debug_run_req, mpc_debug_run_ack; logic o_debug_mode_status; logic lsu_bus_clk_en; assign lsu_bus_clk_en = 1'b1; `else module tb_top import tb_top_pkg::*; #( parameter int MAX_CYCLES = 2_000_000, `include "el2_param.vh" ) ( input bit core_clk, input bit rst_l, input bit [31:0] mem_signature_begin, input bit [31:0] mem_signature_end, input bit [31:0] mem_mailbox, input bit i_cpu_halt_req, // Async halt req to CPU output bit o_cpu_halt_ack, // core response to halt output bit o_cpu_halt_status, // 1'b1 indicates core is halted input bit i_cpu_run_req, // Async restart req to CPU output bit o_cpu_run_ack, // Core response to run req input bit mpc_debug_halt_req, output bit mpc_debug_halt_ack, input bit mpc_debug_run_req, output bit mpc_debug_run_ack, output bit o_debug_mode_status, input bit lsu_bus_clk_en ); `endif `ifdef RV_BUILD_AHB_LITE logic lmem_hsel; logic [31:0] lmem_haddr; logic [2:0] lmem_hburst; logic lmem_hmastlock; logic [3:0] lmem_hprot; logic [2:0] lmem_hsize; logic [1:0] lmem_htrans; logic lmem_hwrite; logic lmem_hreadyout; logic lmem_hreadyin; logic dma_hsel; logic [31:0] dma_haddr; logic [2:0] dma_hburst; logic dma_hmastlock; logic [3:0] dma_hprot; logic [2:0] dma_hsize; logic [1:0] dma_htrans; logic dma_hwrite; logic dma_hreadyout; logic dma_hreadyin; `endif // RV_BUILD_AHB_LITE `ifndef VERILATOR bit core_clk; bit [31:0] mem_signature_begin = 32'd0; // TODO: bit [31:0] mem_signature_end = 32'd0; bit [31:0] mem_mailbox = 32'hD0580000; logic rst_l; `endif logic porst_l; logic [pt.PIC_TOTAL_INT:1] extintsrc_req; logic nmi_int; logic timer_int; logic soft_int; logic [31:0] reset_vector; logic [31:0] nmi_vector; logic [31:1] jtag_id; logic [31:0] ic_haddr ; logic [2:0] ic_hburst ; logic ic_hmastlock ; logic [3:0] ic_hprot ; logic [2:0] ic_hsize ; logic [1:0] ic_htrans ; logic ic_hwrite ; logic [63:0] ic_hrdata ; logic ic_hready ; logic ic_hresp ; logic [31:0] lsu_haddr ; logic [2:0] lsu_hburst ; logic lsu_hmastlock ; logic [3:0] lsu_hprot ; logic [2:0] lsu_hsize ; logic [1:0] lsu_htrans ; logic lsu_hwrite ; logic [63:0] lsu_hrdata ; logic [63:0] lsu_hwdata ; logic lsu_hready ; logic lsu_hresp ; logic [31:0] mux_haddr ; logic [2:0] mux_hburst ; logic mux_hmastlock ; logic [3:0] mux_hprot ; logic [2:0] mux_hsize ; logic [1:0] mux_htrans ; logic mux_hwrite ; logic mux_hsel ; logic [63:0] mux_hrdata ; logic [63:0] mux_hwdata ; logic mux_hready ; logic mux_hresp ; logic mux_hreadyout ; logic [31:0] sb_haddr ; logic [2:0] sb_hburst ; logic sb_hmastlock ; logic [3:0] sb_hprot ; logic [2:0] sb_hsize ; logic [1:0] sb_htrans ; logic sb_hwrite ; logic [63:0] sb_hrdata ; logic [63:0] sb_hwdata ; logic sb_hready ; logic sb_hresp ; logic [31:0] trace_rv_i_insn_ip; logic [31:0] trace_rv_i_address_ip; logic trace_rv_i_valid_ip; logic trace_rv_i_exception_ip; logic [4:0] trace_rv_i_ecause_ip; logic trace_rv_i_interrupt_ip; logic [31:0] trace_rv_i_tval_ip; logic jtag_tdo; logic jtag_tck; logic jtag_tms; logic jtag_tdi; logic jtag_trst_n; logic mailbox_write; logic [63:0] mailbox_data; logic [63:0] lmem_hrdata ; logic [63:0] lmem_hwdata ; logic lmem_hready ; logic lmem_hresp ; logic [63:0] dma_hrdata ; logic [63:0] dma_hwdata ; logic dma_hready ; logic dma_hresp ; logic mpc_reset_run_req; logic debug_brkpt_status; int cycleCnt; logic mailbox_data_val; wire lmem_hready_out; wire dma_hready_out; int commit_count; logic [3:0] nmi_assert_int; logic wb_valid; logic [4:0] wb_dest; logic [31:0] wb_data; logic wb_csr_valid; logic [11:0] wb_csr_dest; logic [31:0] wb_csr_data; logic dmi_core_enable; always_comb dmi_core_enable = ~(o_cpu_halt_status); `ifdef RV_OPENOCD_TEST // SB and LSU AHB master mux ahb_lite_2to1_mux #( .AHB_LITE_ADDR_WIDTH (32), .AHB_LITE_DATA_WIDTH (64), .AHB_NO_OPT(1) //Prevent address and data phase overlap between initiators ) u_sb_lsu_ahb_mux ( .hclk (core_clk), .hreset_n (rst_l), .force_bus_idle (), // Initiator 0 .hsel_i_0 (1'b1 ), .haddr_i_0 (lsu_haddr ), .hwdata_i_0 (lsu_hwdata), .hwrite_i_0 (lsu_hwrite), .htrans_i_0 (lsu_htrans), .hsize_i_0 (lsu_hsize ), .hready_i_0 (lsu_hready), .hresp_o_0 (lsu_hresp ), .hready_o_0 (lsu_hready), .hrdata_o_0 (lsu_hrdata), // Initiator 1 .hsel_i_1 (1'b1 ), .haddr_i_1 (sb_haddr ), .hwdata_i_1 (sb_hwdata ), .hwrite_i_1 (sb_hwrite ), .htrans_i_1 (sb_htrans ), .hsize_i_1 (sb_hsize ), .hready_i_1 (sb_hready ), .hresp_o_1 (sb_hresp ), .hready_o_1 (sb_hready ), .hrdata_o_1 (sb_hrdata ), // Responder .hsel_o (mux_hsel), .haddr_o (mux_haddr ), .hwdata_o (mux_hwdata), .hwrite_o (mux_hwrite), .htrans_o (mux_htrans), .hsize_o (mux_hsize ), .hready_o (mux_hready), .hresp_i (mux_hresp ), .hreadyout_i (mux_hreadyout), .hrdata_i (mux_hrdata) ); `else assign mux_hsel = 1'b1; assign mux_haddr = lsu_haddr; assign mux_hwdata = lsu_hwdata; assign mux_hwrite = lsu_hwrite; assign mux_htrans = lsu_htrans; assign mux_hsize = lsu_hsize; assign lsu_hresp = mux_hresp; assign lsu_hrdata = mux_hrdata; assign lsu_hready = mux_hreadyout; `endif `ifdef RV_BUILD_AXI4 //-------------------------- LSU AXI signals-------------------------- // AXI Write Channels parameter int RV_MUX_BUS_TAG = (`RV_LSU_BUS_TAG > `RV_SB_BUS_TAG ? `RV_LSU_BUS_TAG : `RV_SB_BUS_TAG) + 1; wire lsu_axi_awvalid; wire lsu_axi_awready; wire [`RV_LSU_BUS_TAG-1:0] lsu_axi_awid; wire [31:0] lsu_axi_awaddr; wire [3:0] lsu_axi_awregion; wire [7:0] lsu_axi_awlen; wire [2:0] lsu_axi_awsize; wire [1:0] lsu_axi_awburst; wire lsu_axi_awlock; wire [3:0] lsu_axi_awcache; wire [2:0] lsu_axi_awprot; wire [3:0] lsu_axi_awqos; wire lsu_axi_wvalid; wire lsu_axi_wready; wire [63:0] lsu_axi_wdata; wire [7:0] lsu_axi_wstrb; wire lsu_axi_wlast; wire lsu_axi_bvalid; wire lsu_axi_bready; wire [1:0] lsu_axi_bresp; wire [`RV_LSU_BUS_TAG-1:0] lsu_axi_bid; // AXI Read Channels wire lsu_axi_arvalid; wire lsu_axi_arready; wire [`RV_LSU_BUS_TAG-1:0] lsu_axi_arid; wire [31:0] lsu_axi_araddr; wire [3:0] lsu_axi_arregion; wire [7:0] lsu_axi_arlen; wire [2:0] lsu_axi_arsize; wire [1:0] lsu_axi_arburst; wire lsu_axi_arlock; wire [3:0] lsu_axi_arcache; wire [2:0] lsu_axi_arprot; wire [3:0] lsu_axi_arqos; wire lsu_axi_rvalid; wire lsu_axi_rready; wire [`RV_LSU_BUS_TAG-1:0] lsu_axi_rid; wire [63:0] lsu_axi_rdata; wire [1:0] lsu_axi_rresp; wire lsu_axi_rlast; wire lsu_axi_awuser; wire lsu_axi_wuser; wire lsu_axi_buser; wire lsu_axi_aruser; wire lsu_axi_ruser; //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels wire ifu_axi_awvalid; wire ifu_axi_awready; wire [`RV_IFU_BUS_TAG-1:0] ifu_axi_awid; wire [31:0] ifu_axi_awaddr; wire [3:0] ifu_axi_awregion; wire [7:0] ifu_axi_awlen; wire [2:0] ifu_axi_awsize; wire [1:0] ifu_axi_awburst; wire ifu_axi_awlock; wire [3:0] ifu_axi_awcache; wire [2:0] ifu_axi_awprot; wire [3:0] ifu_axi_awqos; wire ifu_axi_wvalid; wire ifu_axi_wready; wire [63:0] ifu_axi_wdata; wire [7:0] ifu_axi_wstrb; wire ifu_axi_wlast; wire ifu_axi_bvalid; wire ifu_axi_bready; wire [1:0] ifu_axi_bresp; wire [`RV_IFU_BUS_TAG-1:0] ifu_axi_bid; // AXI Read Channels wire ifu_axi_arvalid; wire ifu_axi_arready; wire [`RV_IFU_BUS_TAG-1:0] ifu_axi_arid; wire [31:0] ifu_axi_araddr; wire [3:0] ifu_axi_arregion; wire [7:0] ifu_axi_arlen; wire [2:0] ifu_axi_arsize; wire [1:0] ifu_axi_arburst; wire ifu_axi_arlock; wire [3:0] ifu_axi_arcache; wire [2:0] ifu_axi_arprot; wire [3:0] ifu_axi_arqos; wire ifu_axi_rvalid; wire ifu_axi_rready; wire [`RV_IFU_BUS_TAG-1:0] ifu_axi_rid; wire [63:0] ifu_axi_rdata; wire [1:0] ifu_axi_rresp; wire ifu_axi_rlast; //-------------------------- SB AXI signals-------------------------- // AXI Write Channels wire sb_axi_awvalid; wire sb_axi_awready; wire [`RV_SB_BUS_TAG-1:0] sb_axi_awid; wire [31:0] sb_axi_awaddr; wire [3:0] sb_axi_awregion; wire [7:0] sb_axi_awlen; wire [2:0] sb_axi_awsize; wire [1:0] sb_axi_awburst; wire sb_axi_awlock; wire [3:0] sb_axi_awcache; wire [2:0] sb_axi_awprot; wire [3:0] sb_axi_awqos; wire sb_axi_wvalid; wire sb_axi_wready; wire [63:0] sb_axi_wdata; wire [7:0] sb_axi_wstrb; wire sb_axi_wlast; wire sb_axi_bvalid; wire sb_axi_bready; wire [1:0] sb_axi_bresp; wire [`RV_SB_BUS_TAG-1:0] sb_axi_bid; // AXI Read Channels wire sb_axi_arvalid; wire sb_axi_arready; wire [`RV_SB_BUS_TAG-1:0] sb_axi_arid; wire [31:0] sb_axi_araddr; wire [3:0] sb_axi_arregion; wire [7:0] sb_axi_arlen; wire [2:0] sb_axi_arsize; wire [1:0] sb_axi_arburst; wire sb_axi_arlock; wire [3:0] sb_axi_arcache; wire [2:0] sb_axi_arprot; wire [3:0] sb_axi_arqos; wire sb_axi_rvalid; wire sb_axi_rready; wire [`RV_SB_BUS_TAG-1:0] sb_axi_rid; wire [63:0] sb_axi_rdata; wire [1:0] sb_axi_rresp; wire sb_axi_rlast; wire sb_axi_awuser; wire sb_axi_wuser; wire sb_axi_buser; wire sb_axi_aruser; wire sb_axi_ruser; //-------------------------- DMA AXI signals-------------------------- // AXI Write Channels wire dma_axi_awvalid; wire dma_axi_awready; wire [`RV_DMA_BUS_TAG-1:0] dma_axi_awid; wire [31:0] dma_axi_awaddr; wire [2:0] dma_axi_awsize; wire [2:0] dma_axi_awprot; wire [7:0] dma_axi_awlen; wire [1:0] dma_axi_awburst; wire dma_axi_wvalid; wire dma_axi_wready; wire [63:0] dma_axi_wdata; wire [7:0] dma_axi_wstrb; wire dma_axi_wlast; wire dma_axi_bvalid; wire dma_axi_bready; wire [1:0] dma_axi_bresp; wire [`RV_DMA_BUS_TAG-1:0] dma_axi_bid; // AXI Read Channels wire dma_axi_arvalid; wire dma_axi_arready; wire [`RV_DMA_BUS_TAG-1:0] dma_axi_arid; wire [31:0] dma_axi_araddr; wire [2:0] dma_axi_arsize; wire [2:0] dma_axi_arprot; wire [7:0] dma_axi_arlen; wire [1:0] dma_axi_arburst; wire dma_axi_rvalid; wire dma_axi_rready; wire [`RV_DMA_BUS_TAG-1:0] dma_axi_rid; wire [63:0] dma_axi_rdata; wire [1:0] dma_axi_rresp; wire dma_axi_rlast; wire lmem_axi_arvalid; wire lmem_axi_arready; wire lmem_axi_rvalid; wire [RV_MUX_BUS_TAG-1:0] lmem_axi_rid; wire [1:0] lmem_axi_rresp; wire [63:0] lmem_axi_rdata; wire lmem_axi_rlast; wire lmem_axi_rready; wire lmem_axi_awvalid; wire lmem_axi_awready; wire lmem_axi_wvalid; wire lmem_axi_wready; wire [1:0] lmem_axi_bresp; wire lmem_axi_bvalid; wire [RV_MUX_BUS_TAG-1:0] lmem_axi_bid; wire lmem_axi_bready; wire mux_axi_awvalid; wire mux_axi_awready; wire [RV_MUX_BUS_TAG-1:0] mux_axi_awid; wire [31:0] mux_axi_awaddr; wire [3:0] mux_axi_awregion; wire [7:0] mux_axi_awlen; wire [2:0] mux_axi_awsize; wire [1:0] mux_axi_awburst; wire mux_axi_awlock; wire [3:0] mux_axi_awcache; wire [2:0] mux_axi_awprot; wire [3:0] mux_axi_awqos; wire mux_axi_wvalid; wire mux_axi_wready; wire [63:0] mux_axi_wdata; wire [7:0] mux_axi_wstrb; wire mux_axi_wlast; wire mux_axi_bvalid; wire mux_axi_bready; wire [1:0] mux_axi_bresp; wire [RV_MUX_BUS_TAG-1:0] mux_axi_bid; // AXI Read Channels wire mux_axi_arvalid; wire mux_axi_arready; wire [RV_MUX_BUS_TAG-1:0] mux_axi_arid; wire [31:0] mux_axi_araddr; wire [3:0] mux_axi_arregion; wire [7:0] mux_axi_arlen; wire [2:0] mux_axi_arsize; wire [1:0] mux_axi_arburst; wire mux_axi_arlock; wire [3:0] mux_axi_arcache; wire [2:0] mux_axi_arprot; wire [3:0] mux_axi_arqos; wire mux_axi_rvalid; wire mux_axi_rready; wire [RV_MUX_BUS_TAG-1:0] mux_axi_rid; wire [63:0] mux_axi_rdata; wire [1:0] mux_axi_rresp; wire mux_axi_rlast; wire mux_axi_awuser; wire mux_axi_wuser; wire mux_axi_buser; wire mux_axi_aruser; wire mux_axi_ruser; `ifdef RV_OPENOCD_TEST axi_crossbar_wrap_2x1 #( .ADDR_WIDTH (32), .DATA_WIDTH (64), .S_ID_WIDTH(RV_MUX_BUS_TAG - 1), .M00_ADDR_WIDTH(32) ) u_axi_crossbar ( .clk(core_clk), .rst(!rst_l), // LSU .s00_axi_arvalid(lsu_axi_arvalid), .s00_axi_arready(lsu_axi_arready), .s00_axi_araddr(lsu_axi_araddr), .s00_axi_arid(lsu_axi_arid), .s00_axi_arlen(lsu_axi_arlen), .s00_axi_arburst(lsu_axi_arburst), .s00_axi_arsize(lsu_axi_arsize), .s00_axi_rvalid(lsu_axi_rvalid), .s00_axi_rready(lsu_axi_rready), .s00_axi_rdata(lsu_axi_rdata), .s00_axi_rresp(lsu_axi_rresp), .s00_axi_rid(lsu_axi_rid), .s00_axi_rlast(lsu_axi_rlast), .s00_axi_awvalid(lsu_axi_awvalid), .s00_axi_awready(lsu_axi_awready), .s00_axi_awaddr(lsu_axi_awaddr), .s00_axi_awid(lsu_axi_awid), .s00_axi_awlen(lsu_axi_awlen), .s00_axi_awburst(lsu_axi_awburst), .s00_axi_awlock(lsu_axi_awlock), .s00_axi_awcache(lsu_axi_awcache), .s00_axi_awprot(lsu_axi_awprot), .s00_axi_awqos(lsu_axi_awqos), .s00_axi_awuser(lsu_axi_awuser), .s00_axi_wlast(lsu_axi_wlast), .s00_axi_wuser(lsu_axi_wuser), .s00_axi_buser(lsu_axi_buser), .s00_axi_arlock(lsu_axi_arlock), .s00_axi_arcache(lsu_axi_arcache), .s00_axi_arprot(lsu_axi_arprot), .s00_axi_arqos(lsu_axi_arqos), .s00_axi_aruser(lsu_axi_aruser), .s00_axi_ruser(lsu_axi_ruser), .s00_axi_awsize(lsu_axi_awsize), .s00_axi_wdata(lsu_axi_wdata), .s00_axi_wstrb(lsu_axi_wstrb), .s00_axi_wvalid(lsu_axi_wvalid), .s00_axi_wready(lsu_axi_wready), .s00_axi_bvalid(lsu_axi_bvalid), .s00_axi_bready(lsu_axi_bready), .s00_axi_bresp(lsu_axi_bresp), .s00_axi_bid(lsu_axi_bid), // SB .s01_axi_arvalid(sb_axi_arvalid), .s01_axi_arready(sb_axi_arready), .s01_axi_araddr(sb_axi_araddr), .s01_axi_arid(sb_axi_arid), .s01_axi_arlen(sb_axi_arlen), .s01_axi_arburst(sb_axi_arburst), .s01_axi_arsize(sb_axi_arsize), .s01_axi_rvalid(sb_axi_rvalid), .s01_axi_rready(sb_axi_rready), .s01_axi_rdata(sb_axi_rdata), .s01_axi_rresp(sb_axi_rresp), .s01_axi_rid(sb_axi_rid), .s01_axi_rlast(sb_axi_rlast), .s01_axi_awvalid(sb_axi_awvalid), .s01_axi_awready(sb_axi_awready), .s01_axi_awaddr(sb_axi_awaddr), .s01_axi_awid(sb_axi_awid), .s01_axi_awlen(sb_axi_awlen), .s01_axi_awburst(sb_axi_awburst), .s01_axi_awlock(sb_axi_awlock), .s01_axi_awcache(sb_axi_awcache), .s01_axi_awprot(sb_axi_awprot), .s01_axi_awqos(sb_axi_awqos), .s01_axi_awuser(sb_axi_awuser), .s01_axi_wlast(sb_axi_wlast), .s01_axi_wuser(sb_axi_wuser), .s01_axi_buser(sb_axi_buser), .s01_axi_arlock(sb_axi_arlock), .s01_axi_arcache(sb_axi_arcache), .s01_axi_arprot(sb_axi_arprot), .s01_axi_arqos(sb_axi_arqos), .s01_axi_aruser(sb_axi_aruser), .s01_axi_ruser(sb_axi_ruser), .s01_axi_awsize(sb_axi_awsize), .s01_axi_wdata(sb_axi_wdata), .s01_axi_wstrb(sb_axi_wstrb), .s01_axi_wvalid(sb_axi_wvalid), .s01_axi_wready(sb_axi_wready), .s01_axi_bvalid(sb_axi_bvalid), .s01_axi_bready(sb_axi_bready), .s01_axi_bresp(sb_axi_bresp), .s01_axi_bid(sb_axi_bid), // Output .m00_axi_arvalid(mux_axi_arvalid), .m00_axi_arready(mux_axi_arready), .m00_axi_araddr(mux_axi_araddr), .m00_axi_arid(mux_axi_arid), .m00_axi_arlen(mux_axi_arlen), .m00_axi_arburst(mux_axi_arburst), .m00_axi_arsize(mux_axi_arsize), .m00_axi_rvalid(mux_axi_rvalid), .m00_axi_rready(mux_axi_rready), .m00_axi_rdata(mux_axi_rdata), .m00_axi_rresp(mux_axi_rresp), .m00_axi_rid(mux_axi_rid), .m00_axi_rlast(mux_axi_rlast), .m00_axi_awvalid(mux_axi_awvalid), .m00_axi_awready(mux_axi_awready), .m00_axi_awaddr(mux_axi_awaddr), .m00_axi_awid(mux_axi_awid), .m00_axi_awlen(mux_axi_awlen), .m00_axi_awburst(mux_axi_awburst), .m00_axi_awlock(mux_axi_awlock), .m00_axi_awcache(mux_axi_awcache), .m00_axi_awprot(mux_axi_awprot), .m00_axi_awqos(mux_axi_awqos), .m00_axi_awuser(mux_axi_awuser), .m00_axi_wlast(mux_axi_wlast), .m00_axi_wuser(mux_axi_wuser), .m00_axi_buser(mux_axi_buser), .m00_axi_arlock(mux_axi_arlock), .m00_axi_arcache(mux_axi_arcache), .m00_axi_arprot(mux_axi_arprot), .m00_axi_arqos(mux_axi_arqos), .m00_axi_aruser(mux_axi_aruser), .m00_axi_ruser(mux_axi_ruser), .m00_axi_awsize(mux_axi_awsize), .m00_axi_wdata(mux_axi_wdata), .m00_axi_wstrb(mux_axi_wstrb), .m00_axi_wvalid(mux_axi_wvalid), .m00_axi_wready(mux_axi_wready), .m00_axi_bvalid(mux_axi_bvalid), .m00_axi_bready(mux_axi_bready), .m00_axi_bresp(mux_axi_bresp), .m00_axi_bid(mux_axi_bid), .m00_axi_awregion(mux_axi_awregion), .m00_axi_arregion(mux_axi_arregion) ); `else assign mux_axi_arvalid = lsu_axi_arvalid; assign lsu_axi_arready = mux_axi_arready; assign mux_axi_araddr = lsu_axi_araddr; assign mux_axi_arid = lsu_axi_arid; assign mux_axi_arlen = lsu_axi_arlen; assign mux_axi_arburst = lsu_axi_arburst; assign mux_axi_arsize = lsu_axi_arsize; assign lsu_axi_rvalid = mux_axi_rvalid; assign mux_axi_rready = lsu_axi_rready; assign lsu_axi_rdata = mux_axi_rdata; assign lsu_axi_rresp = mux_axi_rresp; assign lsu_axi_rid = mux_axi_rid; assign lsu_axi_rlast = mux_axi_rlast; assign mux_axi_awvalid = lsu_axi_awvalid; assign lsu_axi_awready = mux_axi_awready; assign mux_axi_awaddr = lsu_axi_awaddr; assign mux_axi_awid = lsu_axi_awid; assign mux_axi_awlen = lsu_axi_awlen; assign mux_axi_awburst = lsu_axi_awburst; assign mux_axi_awlock = lsu_axi_awlock; assign mux_axi_awcache = lsu_axi_awcache; assign mux_axi_awprot = lsu_axi_awprot; assign mux_axi_awqos = lsu_axi_awqos; assign mux_axi_awuser = lsu_axi_awuser; assign mux_axi_wlast = lsu_axi_wlast; assign mux_axi_wuser = lsu_axi_wuser; assign lsu_axi_buser = mux_axi_buser; assign mux_axi_arlock = lsu_axi_arlock; assign mux_axi_arcache = lsu_axi_arcache; assign mux_axi_arprot = lsu_axi_arprot; assign mux_axi_arqos = lsu_axi_arqos; assign mux_axi_aruser = lsu_axi_aruser; assign lsu_axi_ruser = mux_axi_ruser; assign mux_axi_awsize = lsu_axi_awsize; assign mux_axi_wdata = lsu_axi_wdata; assign mux_axi_wstrb = lsu_axi_wstrb; assign mux_axi_wvalid = lsu_axi_wvalid; assign lsu_axi_wready = mux_axi_wready; assign lsu_axi_bvalid = mux_axi_bvalid; assign mux_axi_bready = lsu_axi_bready; assign lsu_axi_bresp = mux_axi_bresp; assign lsu_axi_bid = mux_axi_bid; assign mux_axi_awregion = lsu_axi_awregion; assign mux_axi_arregion = lsu_axi_arregion; `endif `endif string abi_reg[32]; // ABI register names el2_mem_if el2_mem_export (); logic [pt.ICCM_NUM_BANKS-1:0][ 38:0] iccm_bank_wr_fdata; logic [pt.ICCM_NUM_BANKS-1:0][ 38:0] iccm_bank_fdout; logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_fdata_bank; logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_FDATA_WIDTH-1:0] dccm_bank_fdout; tb_top_pkg::veer_sram_error_injection_mode_t error_injection_mode; `define DEC rvtop_wrapper.rvtop.veer.dec `ifdef RV_BUILD_AHB_LITE always_ff @(posedge core_clk) mailbox_write <= lmem.HSEL && lmem.HREADY && lmem.HADDR == mem_mailbox && rst_l; assign mailbox_data = lmem.HWDATA; `endif `ifdef RV_BUILD_AXI4 assign mailbox_write = lmem.awvalid && lmem.awaddr == mem_mailbox && rst_l; assign mailbox_data = lmem.wdata; `endif assign mailbox_data_val = mailbox_data[7:0] > 8'h5 && mailbox_data[7:0] < 8'h7f; integer fd, tp, el; logic next_dbus_error; logic next_ibus_error; always @(negedge core_clk or negedge rst_l) begin if (rst_l == 0) begin error_injection_mode <= '0; next_dbus_error <= '0; next_ibus_error <= '0; end else begin nmi_assert_int <= nmi_assert_int >> 1; soft_int <= 0; timer_int <= 0; extintsrc_req[1] <= 0; cycleCnt <= cycleCnt+1; // timeout monitor if(cycleCnt == MAX_CYCLES) begin $display ("Hit max cycle count (%0d) .. stopping", cycleCnt); $display("TEST_FAILED"); `ifdef TB_SILENT_FAIL $finish; `else $fatal; `endif // TB_SILENT_FAIL end // console Monitor if( mailbox_data_val & mailbox_write) begin $fwrite(fd,"%c", mailbox_data[7:0]); $write("%c", mailbox_data[7:0]); end // Interrupt signals control // data[7:0] == 0x80 - clear ext irq line index given by data[15:8] // data[7:0] == 0x81 - set ext irq line index given by data[15:8] // data[7:0] == 0x82 - clean NMI, timer and soft irq lines to bits data[8:10] // data[7:0] == 0x83 - set NMI, timer and soft irq lines to bits data[8:10] // data[7:0] == 0x86 - Trigger external interrupt // data[7:0] == 0x87 - (AXI4) Trigger data bus error on the next load/store // data[7:0] == 0x88 - (AXI4) Trigger instruction bus error on the next load/store // data[7:0] == 0x90 - clear all interrupt request signals if(mailbox_write && (mailbox_data[7:0] >= 8'h80 && mailbox_data[7:0] < 8'h87)) begin if (mailbox_data[7:0] == 8'h80) begin if (mailbox_data[15:8] > 0 && mailbox_data[15:8] < pt.PIC_TOTAL_INT && nmi_assert_int == 4'b0000) extintsrc_req[mailbox_data[15:8]] <= 1'b0; nmi_assert_int <= 4'b1111; end if (mailbox_data[7:0] == 8'h81) begin if (mailbox_data[15:8] > 0 && mailbox_data[15:8] < pt.PIC_TOTAL_INT) extintsrc_req[mailbox_data[15:8]] <= 1'b1; nmi_vector[31:1] <= {mailbox_data[31:8], 7'h00}; end if (mailbox_data[7:0] == 8'h82 && nmi_assert_int == 4'b0000) begin nmi_assert_int <= {4{nmi_int & ~mailbox_data[8]}}; timer_int <= timer_int & ~mailbox_data[9]; soft_int <= soft_int & ~mailbox_data[10]; end if (mailbox_data[7:0] == 8'h83 && nmi_assert_int == 4'b0000) begin nmi_assert_int <= {4{nmi_int | mailbox_data[8]}}; timer_int <= timer_int | mailbox_data[9]; soft_int <= soft_int | mailbox_data[10]; end if (mailbox_data[7:0] == 8'h84) begin soft_int <= 1; end if (mailbox_data[7:0] == 8'h85) begin timer_int <= 1; end if (mailbox_data[7:0] == 8'h86) begin extintsrc_req[1] <= 1; end end if(mailbox_write && (mailbox_data[7:0] == 8'h90)) begin extintsrc_req <= {pt.PIC_TOTAL_INT-1{1'b0}}; nmi_assert_int <= 4'b0000; timer_int <= 1'b0; soft_int <= 1'b0; end // end // ECC error injection if(mailbox_write && (mailbox_data[7:0] == 8'he0)) begin $display("Injecting single bit ICCM error"); error_injection_mode.iccm_single_bit_error <= 1'b1; end else if(mailbox_write && (mailbox_data[7:0] == 8'he1)) begin $display("Injecting double bit ICCM error"); error_injection_mode.iccm_double_bit_error <= 1'b1; end else if(mailbox_write && (mailbox_data[7:0] == 8'he2)) begin $display("Injecting single bit DCCM error"); error_injection_mode.dccm_single_bit_error <= 1'b1; end else if(mailbox_write && (mailbox_data[7:0] == 8'he3)) begin $display("Injecting double bit DCCM error"); error_injection_mode.dccm_double_bit_error <= 1'b1; end else if(mailbox_write && (mailbox_data[7:0] == 8'he4)) begin $display("Disable ECC error injection"); error_injection_mode <= '0; end // Memory signature dump if(mailbox_write && (mailbox_data[7:0] == 8'hFF || mailbox_data[7:0] == 8'h01)) begin if (mem_signature_begin < mem_signature_end) begin dump_signature(); end end // End Of test monitor if(mailbox_write && mailbox_data[7:0] == 8'hff) begin $display("TEST_PASSED"); $display("\nFinished : minstret = %0d, mcycle = %0d", `DEC.tlu.minstretl[31:0],`DEC.tlu.mcyclel[31:0]); $display("See \"exec.log\" for execution trace with register updates..\n"); // OpenOCD test breaks if simulation closes the TCP connection first. // This delay allows OpenOCD to close the connection before the #finish. #15000; $finish; end else if(mailbox_write && mailbox_data[7:0] == 8'h1) begin $display("TEST_FAILED"); `ifdef TB_SILENT_FAIL $finish; `else $fatal; `endif // TB_SILENT_FAIL end end end `ifdef RV_BUILD_AXI4 // this needs to be a separate block due to sensitivity to other signals always @(negedge core_clk or lsu_axi_bvalid or lsu_axi_rvalid or ifu_axi_rvalid or ifu_axi_rid) begin if (mailbox_write && mailbox_data[7:0] == 8'h87) // wait for current transaction that to complete to not trigger error on it @(negedge lsu_axi_bvalid) next_dbus_error <= 1; if (mailbox_write && mailbox_data[7:0] == 8'h88) @(negedge ifu_axi_rvalid or ifu_axi_rid) next_ibus_error <= 1; // turn off forcing dbus error after a transaction if (next_dbus_error) @(negedge lsu_axi_bvalid or negedge lsu_axi_rvalid) next_dbus_error <= 0; if (next_ibus_error) @(negedge ifu_axi_rvalid or ifu_axi_rid) next_ibus_error <= 0; end logic [1:0] lsu_axi_rresp_override; logic [1:0] lsu_axi_bresp_override; logic [1:0] ifu_axi_rresp_override; always_comb begin lsu_axi_rresp_override = lsu_axi_rresp; lsu_axi_bresp_override = lsu_axi_bresp; ifu_axi_rresp_override = ifu_axi_rresp; if (next_dbus_error) begin // force slave bus error if (lsu_axi_rvalid) lsu_axi_rresp_override = 2'b10; if (lsu_axi_bvalid) lsu_axi_bresp_override = 2'b10; end if (next_ibus_error) begin if (ifu_axi_rvalid) ifu_axi_rresp_override = 2'b10; end end `endif // nmi_int must be asserted for at least two clock cycles and then deasserted for // at least two clock cycles - see RISC-V VeeR EL2 Programmer's Reference Manual section 2.16 assign nmi_int = |{nmi_assert_int[3:2]}; // trace monitor always @(posedge core_clk) begin wb_valid <= `DEC.dec_i0_wen_r; wb_dest <= `DEC.dec_i0_waddr_r; wb_data <= `DEC.dec_i0_wdata_r; wb_csr_valid <= `DEC.dec_csr_wen_r; wb_csr_dest <= `DEC.dec_csr_wraddr_r; wb_csr_data <= `DEC.dec_csr_wrdata_r; if (trace_rv_i_valid_ip) begin $fwrite(tp,"%b,%h,%h,%0h,%0h,3,%b,%h,%h,%b\n", trace_rv_i_valid_ip, 0, trace_rv_i_address_ip, 0, trace_rv_i_insn_ip,trace_rv_i_exception_ip,trace_rv_i_ecause_ip, trace_rv_i_tval_ip,trace_rv_i_interrupt_ip); // Basic trace - no exception register updates // #1 0 ee000000 b0201073 c 0b02 00000000 commit_count++; $fwrite (el, "%10d : %8s 0 %h %h%13s %14s ; %s\n", cycleCnt, $sformatf("#%0d",commit_count), trace_rv_i_address_ip, trace_rv_i_insn_ip, (wb_dest !=0 && wb_valid)? $sformatf("%s=%h", abi_reg[wb_dest], wb_data) : " ", (wb_csr_valid)? $sformatf("c%h=%h", wb_csr_dest, wb_csr_data) : " ", dasm(trace_rv_i_insn_ip, trace_rv_i_address_ip, wb_dest & {5{wb_valid}}, wb_data) ); end if(`DEC.dec_nonblock_load_wen) begin $fwrite (el, "%10d : %32s=%h ; nbL\n", cycleCnt, abi_reg[`DEC.dec_nonblock_load_waddr], `DEC.lsu_nonblock_load_data); tb_top.gpr[0][`DEC.dec_nonblock_load_waddr] = `DEC.lsu_nonblock_load_data; end if(`DEC.exu_div_wren) begin $fwrite (el, "%10d : %32s=%h ; nbD\n", cycleCnt, abi_reg[`DEC.div_waddr_wb], `DEC.exu_div_result); tb_top.gpr[0][`DEC.div_waddr_wb] = `DEC.exu_div_result; end end initial begin abi_reg[0] = "zero"; abi_reg[1] = "ra"; abi_reg[2] = "sp"; abi_reg[3] = "gp"; abi_reg[4] = "tp"; abi_reg[5] = "t0"; abi_reg[6] = "t1"; abi_reg[7] = "t2"; abi_reg[8] = "s0"; abi_reg[9] = "s1"; abi_reg[10] = "a0"; abi_reg[11] = "a1"; abi_reg[12] = "a2"; abi_reg[13] = "a3"; abi_reg[14] = "a4"; abi_reg[15] = "a5"; abi_reg[16] = "a6"; abi_reg[17] = "a7"; abi_reg[18] = "s2"; abi_reg[19] = "s3"; abi_reg[20] = "s4"; abi_reg[21] = "s5"; abi_reg[22] = "s6"; abi_reg[23] = "s7"; abi_reg[24] = "s8"; abi_reg[25] = "s9"; abi_reg[26] = "s10"; abi_reg[27] = "s11"; abi_reg[28] = "t3"; abi_reg[29] = "t4"; abi_reg[30] = "t5"; abi_reg[31] = "t6"; extintsrc_req = {pt.PIC_TOTAL_INT-1{1'b0}}; timer_int = 0; soft_int = 0; // tie offs jtag_id[31:28] = 4'b1; jtag_id[27:12] = '0; jtag_id[11:1] = 11'h45; reset_vector = `RV_RESET_VEC; nmi_assert_int = 0; nmi_vector = 32'hee000000; $readmemh("program.hex", lmem.mem); $readmemh("program.hex", imem.mem); tp = $fopen("trace_port.csv","w"); el = $fopen("exec.log","w"); $fwrite (el, "// Cycle : #inst 0 pc opcode reg=value csr=value ; mnemonic\n"); fd = $fopen("console.log","w"); commit_count = 0; preload_dccm(); preload_iccm(); `ifndef VERILATOR $dumpfile("dump.vcd"); $dumpvars(0, tb_top); rst_l = 1'b1; rst_l = #5 1'b0; rst_l = #25 1'b1; // halt and start the core i_cpu_halt_req = 1'b0; i_cpu_run_req = 1'b0; mpc_debug_halt_req = 1'b0; mpc_debug_run_req = 1'b0; $display("halting CPU and waiting for ack"); i_cpu_halt_req = #5 1'b1; wait(o_cpu_halt_ack == 1); $display("waiting for halt"); i_cpu_halt_req = 1'b0; wait(o_cpu_halt_status == 1'b1); $display("requesting start and waiting for ack"); i_cpu_run_req = 1'b1; wait(o_cpu_run_ack == 1'b1); $display("waiting for run"); i_cpu_run_req = 1'b0; wait(o_cpu_halt_status == 1'b0); $display("done"); $display("requesting mpc halt and wating for ack"); mpc_debug_halt_req = 1'b1; wait(mpc_debug_halt_ack == 1'b1); $display("waiting for debug halt"); mpc_debug_halt_req = 1'b0; wait(o_debug_mode_status == 1'b1); $display("requesting start and waiting for ack"); mpc_debug_run_req = 1'b1; wait(mpc_debug_run_ack == 1'b1); $display("waiting for cpu to start"); mpc_debug_run_req = 1'b0; wait(o_debug_mode_status == 1'b0); $display("done"); `endif end `ifndef VERILATOR initial begin forever core_clk = #5 ~core_clk; end initial begin porst_l = 1'b1; porst_l = #1 1'b0; porst_l = #10 1'b1; end `else assign porst_l = cycleCnt > 2; `endif //=========================================================================- // RTL instance //=========================================================================- veer_wrapper rvtop_wrapper ( .rst_l ( rst_l ), .dbg_rst_l ( porst_l ), .clk ( core_clk ), .rst_vec ( reset_vector[31:1]), .nmi_int ( nmi_int ), .nmi_vec ( nmi_vector[31:1]), .jtag_id ( jtag_id[31:1]), `ifdef RV_BUILD_AHB_LITE .haddr ( ic_haddr ), .hburst ( ic_hburst ), .hmastlock ( ic_hmastlock ), .hprot ( ic_hprot ), .hsize ( ic_hsize ), .htrans ( ic_htrans ), .hwrite ( ic_hwrite ), .hrdata ( ic_hrdata[63:0]), .hready ( ic_hready ), .hresp ( ic_hresp ), //--------------------------------------------------------------- // Debug AHB Master //--------------------------------------------------------------- .sb_haddr ( sb_haddr ), .sb_hburst ( sb_hburst ), .sb_hmastlock ( sb_hmastlock ), .sb_hprot ( sb_hprot ), .sb_hsize ( sb_hsize ), .sb_htrans ( sb_htrans ), .sb_hwrite ( sb_hwrite ), .sb_hwdata ( sb_hwdata ), .sb_hrdata ( sb_hrdata ), .sb_hready ( sb_hready ), .sb_hresp ( sb_hresp ), //--------------------------------------------------------------- // LSU AHB Master //--------------------------------------------------------------- .lsu_haddr ( lsu_haddr ), .lsu_hburst ( lsu_hburst ), .lsu_hmastlock ( lsu_hmastlock ), .lsu_hprot ( lsu_hprot ), .lsu_hsize ( lsu_hsize ), .lsu_htrans ( lsu_htrans ), .lsu_hwrite ( lsu_hwrite ), .lsu_hwdata ( lsu_hwdata ), .lsu_hrdata ( lsu_hrdata[63:0]), .lsu_hready ( lsu_hready ), .lsu_hresp ( lsu_hresp ), //--------------------------------------------------------------- // DMA Slave //--------------------------------------------------------------- .dma_haddr (dma_haddr), .dma_hburst (dma_hburst), .dma_hmastlock (dma_hmastlock), .dma_hprot (dma_hprot), .dma_hsize (dma_hsize), .dma_htrans (dma_htrans), .dma_hwrite (dma_hwrite), .dma_hwdata (dma_hwdata), .dma_hrdata ( dma_hrdata ), .dma_hresp ( dma_hresp ), .dma_hsel ( dma_hsel ), .dma_hreadyin ( dma_hready_out ), .dma_hreadyout ( dma_hready_out ), `endif // RV_BUILD_AHB_LITE `ifdef RV_BUILD_AXI4 //-------------------------- LSU AXI signals-------------------------- // AXI Write Channels .lsu_axi_awvalid (lsu_axi_awvalid), .lsu_axi_awready (lsu_axi_awready), .lsu_axi_awid (lsu_axi_awid), .lsu_axi_awaddr (lsu_axi_awaddr), .lsu_axi_awregion (lsu_axi_awregion), .lsu_axi_awlen (lsu_axi_awlen), .lsu_axi_awsize (lsu_axi_awsize), .lsu_axi_awburst (lsu_axi_awburst), .lsu_axi_awlock (lsu_axi_awlock), .lsu_axi_awcache (lsu_axi_awcache), .lsu_axi_awprot (lsu_axi_awprot), .lsu_axi_awqos (lsu_axi_awqos), .lsu_axi_wvalid (lsu_axi_wvalid), .lsu_axi_wready (lsu_axi_wready), .lsu_axi_wdata (lsu_axi_wdata), .lsu_axi_wstrb (lsu_axi_wstrb), .lsu_axi_wlast (lsu_axi_wlast), .lsu_axi_bvalid (lsu_axi_bvalid), .lsu_axi_bready (lsu_axi_bready), .lsu_axi_bresp (lsu_axi_bresp_override), .lsu_axi_bid (lsu_axi_bid), .lsu_axi_arvalid (lsu_axi_arvalid), .lsu_axi_arready (lsu_axi_arready), .lsu_axi_arid (lsu_axi_arid), .lsu_axi_araddr (lsu_axi_araddr), .lsu_axi_arregion (lsu_axi_arregion), .lsu_axi_arlen (lsu_axi_arlen), .lsu_axi_arsize (lsu_axi_arsize), .lsu_axi_arburst (lsu_axi_arburst), .lsu_axi_arlock (lsu_axi_arlock), .lsu_axi_arcache (lsu_axi_arcache), .lsu_axi_arprot (lsu_axi_arprot), .lsu_axi_arqos (lsu_axi_arqos), .lsu_axi_rvalid (lsu_axi_rvalid), .lsu_axi_rready (lsu_axi_rready), .lsu_axi_rid (lsu_axi_rid), .lsu_axi_rdata (lsu_axi_rdata), .lsu_axi_rresp (lsu_axi_rresp_override), .lsu_axi_rlast (lsu_axi_rlast), //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels .ifu_axi_awvalid (ifu_axi_awvalid), .ifu_axi_awready (ifu_axi_awready), .ifu_axi_awid (ifu_axi_awid), .ifu_axi_awaddr (ifu_axi_awaddr), .ifu_axi_awregion (ifu_axi_awregion), .ifu_axi_awlen (ifu_axi_awlen), .ifu_axi_awsize (ifu_axi_awsize), .ifu_axi_awburst (ifu_axi_awburst), .ifu_axi_awlock (ifu_axi_awlock), .ifu_axi_awcache (ifu_axi_awcache), .ifu_axi_awprot (ifu_axi_awprot), .ifu_axi_awqos (ifu_axi_awqos), .ifu_axi_wvalid (ifu_axi_wvalid), .ifu_axi_wready (ifu_axi_wready), .ifu_axi_wdata (ifu_axi_wdata), .ifu_axi_wstrb (ifu_axi_wstrb), .ifu_axi_wlast (ifu_axi_wlast), .ifu_axi_bvalid (ifu_axi_bvalid), .ifu_axi_bready (ifu_axi_bready), .ifu_axi_bresp (ifu_axi_bresp), .ifu_axi_bid (ifu_axi_bid), .ifu_axi_arvalid (ifu_axi_arvalid), .ifu_axi_arready (ifu_axi_arready), .ifu_axi_arid (ifu_axi_arid), .ifu_axi_araddr (ifu_axi_araddr), .ifu_axi_arregion (ifu_axi_arregion), .ifu_axi_arlen (ifu_axi_arlen), .ifu_axi_arsize (ifu_axi_arsize), .ifu_axi_arburst (ifu_axi_arburst), .ifu_axi_arlock (ifu_axi_arlock), .ifu_axi_arcache (ifu_axi_arcache), .ifu_axi_arprot (ifu_axi_arprot), .ifu_axi_arqos (ifu_axi_arqos), .ifu_axi_rvalid (ifu_axi_rvalid), .ifu_axi_rready (ifu_axi_rready), .ifu_axi_rid (ifu_axi_rid), .ifu_axi_rdata (ifu_axi_rdata), .ifu_axi_rresp (ifu_axi_rresp_override), .ifu_axi_rlast (ifu_axi_rlast), //-------------------------- SB AXI signals-------------------------- // AXI Write Channels .sb_axi_awvalid (sb_axi_awvalid), .sb_axi_awready (sb_axi_awready), .sb_axi_awid (sb_axi_awid), .sb_axi_awaddr (sb_axi_awaddr), .sb_axi_awregion (sb_axi_awregion), .sb_axi_awlen (sb_axi_awlen), .sb_axi_awsize (sb_axi_awsize), .sb_axi_awburst (sb_axi_awburst), .sb_axi_awlock (sb_axi_awlock), .sb_axi_awcache (sb_axi_awcache), .sb_axi_awprot (sb_axi_awprot), .sb_axi_awqos (sb_axi_awqos), .sb_axi_wvalid (sb_axi_wvalid), .sb_axi_wready (sb_axi_wready), .sb_axi_wdata (sb_axi_wdata), .sb_axi_wstrb (sb_axi_wstrb), .sb_axi_wlast (sb_axi_wlast), .sb_axi_bvalid (sb_axi_bvalid), .sb_axi_bready (sb_axi_bready), .sb_axi_bresp (sb_axi_bresp), .sb_axi_bid (sb_axi_bid), .sb_axi_arvalid (sb_axi_arvalid), .sb_axi_arready (sb_axi_arready), .sb_axi_arid (sb_axi_arid), .sb_axi_araddr (sb_axi_araddr), .sb_axi_arregion (sb_axi_arregion), .sb_axi_arlen (sb_axi_arlen), .sb_axi_arsize (sb_axi_arsize), .sb_axi_arburst (sb_axi_arburst), .sb_axi_arlock (sb_axi_arlock), .sb_axi_arcache (sb_axi_arcache), .sb_axi_arprot (sb_axi_arprot), .sb_axi_arqos (sb_axi_arqos), .sb_axi_rvalid (sb_axi_rvalid), .sb_axi_rready (sb_axi_rready), .sb_axi_rid (sb_axi_rid), .sb_axi_rdata (sb_axi_rdata), .sb_axi_rresp (sb_axi_rresp), .sb_axi_rlast (sb_axi_rlast), //-------------------------- DMA AXI signals-------------------------- // AXI Write Channels .dma_axi_awvalid (dma_axi_awvalid), .dma_axi_awready (dma_axi_awready), .dma_axi_awid ('0), .dma_axi_awaddr (lsu_axi_awaddr), .dma_axi_awsize (lsu_axi_awsize), .dma_axi_awprot (lsu_axi_awprot), .dma_axi_awlen (lsu_axi_awlen), .dma_axi_awburst (lsu_axi_awburst), .dma_axi_wvalid (dma_axi_wvalid), .dma_axi_wready (dma_axi_wready), .dma_axi_wdata (lsu_axi_wdata), .dma_axi_wstrb (lsu_axi_wstrb), .dma_axi_wlast (lsu_axi_wlast), .dma_axi_bvalid (dma_axi_bvalid), .dma_axi_bready (dma_axi_bready), .dma_axi_bresp (dma_axi_bresp), .dma_axi_bid (), .dma_axi_arvalid (dma_axi_arvalid), .dma_axi_arready (dma_axi_arready), .dma_axi_arid ('0), .dma_axi_araddr (lsu_axi_araddr), .dma_axi_arsize (lsu_axi_arsize), .dma_axi_arprot (lsu_axi_arprot), .dma_axi_arlen (lsu_axi_arlen), .dma_axi_arburst (lsu_axi_arburst), .dma_axi_rvalid (dma_axi_rvalid), .dma_axi_rready (dma_axi_rready), .dma_axi_rid (), .dma_axi_rdata (dma_axi_rdata), .dma_axi_rresp (dma_axi_rresp), .dma_axi_rlast (dma_axi_rlast), `endif .timer_int ( timer_int ), .extintsrc_req ( extintsrc_req ), .lsu_bus_clk_en (lsu_bus_clk_en),// Clock ratio b/w cpu core clk & AHB master interface .ifu_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB master interface .dbg_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB Debug master interface .dma_bus_clk_en ( 1'b1 ),// Clock ratio b/w cpu core clk & AHB slave interface .trace_rv_i_insn_ip (trace_rv_i_insn_ip), .trace_rv_i_address_ip (trace_rv_i_address_ip), .trace_rv_i_valid_ip (trace_rv_i_valid_ip), .trace_rv_i_exception_ip(trace_rv_i_exception_ip), .trace_rv_i_ecause_ip (trace_rv_i_ecause_ip), .trace_rv_i_interrupt_ip(trace_rv_i_interrupt_ip), .trace_rv_i_tval_ip (trace_rv_i_tval_ip), .jtag_tck (jtag_tck), .jtag_tms (jtag_tms), .jtag_tdi (jtag_tdi), .jtag_trst_n (jtag_trst_n), .jtag_tdo (jtag_tdo), .jtag_tdoEn (), .mpc_debug_halt_ack ( mpc_debug_halt_ack), .mpc_debug_halt_req ( mpc_debug_halt_req), .mpc_debug_run_ack ( mpc_debug_run_ack), .mpc_debug_run_req ( mpc_debug_run_req), .mpc_reset_run_req ( 1'b1), // Start running after reset .debug_brkpt_status (debug_brkpt_status), .i_cpu_halt_req ( i_cpu_halt_req ), // Async halt req to CPU .o_cpu_halt_ack ( o_cpu_halt_ack ), // core response to halt .o_cpu_halt_status ( o_cpu_halt_status ), // 1'b1 indicates core is halted .i_cpu_run_req ( i_cpu_run_req ), // Async restart req to CPU .o_debug_mode_status ( o_debug_mode_status), .o_cpu_run_ack ( o_cpu_run_ack ), // Core response to run req .dec_tlu_perfcnt0 (), .dec_tlu_perfcnt1 (), .dec_tlu_perfcnt2 (), .dec_tlu_perfcnt3 (), .mem_clk (el2_mem_export.clk), .iccm_clken (el2_mem_export.iccm_clken), .iccm_wren_bank (el2_mem_export.iccm_wren_bank), .iccm_addr_bank (el2_mem_export.iccm_addr_bank), .iccm_bank_wr_data (el2_mem_export.iccm_bank_wr_data), .iccm_bank_wr_ecc (el2_mem_export.iccm_bank_wr_ecc), .iccm_bank_dout (el2_mem_export.iccm_bank_dout), .iccm_bank_ecc (el2_mem_export.iccm_bank_ecc), .dccm_clken (el2_mem_export.dccm_clken), .dccm_wren_bank (el2_mem_export.dccm_wren_bank), .dccm_addr_bank (el2_mem_export.dccm_addr_bank), .dccm_wr_data_bank (el2_mem_export.dccm_wr_data_bank), .dccm_wr_ecc_bank (el2_mem_export.dccm_wr_ecc_bank), .dccm_bank_dout (el2_mem_export.dccm_bank_dout), .dccm_bank_ecc (el2_mem_export.dccm_bank_ecc), .ic_tag_clken_final (el2_mem_export.ic_tag_clken_final), .ic_tag_wren_q (el2_mem_export.ic_tag_wren_q), .ic_tag_wren_biten_vec (el2_mem_export.ic_tag_wren_biten_vec), .ic_tag_wr_data (el2_mem_export.ic_tag_wr_data), .ic_rw_addr_q (el2_mem_export.ic_rw_addr_q), .ic_tag_data_raw_packed_pre (el2_mem_export.ic_tag_data_raw_packed_pre), .ic_tag_data_raw_pre (el2_mem_export.ic_tag_data_raw_pre), .ic_b_sb_wren (el2_mem_export.ic_b_sb_wren), .ic_b_sb_bit_en_vec (el2_mem_export.ic_b_sb_bit_en_vec), .ic_sb_wr_data (el2_mem_export.ic_sb_wr_data), .ic_rw_addr_bank_q (el2_mem_export.ic_rw_addr_bank_q), .wb_packeddout_pre (el2_mem_export.wb_packeddout_pre), .ic_bank_way_clken_final (el2_mem_export.ic_bank_way_clken_final), .ic_bank_way_clken_final_up (el2_mem_export.ic_bank_way_clken_final_up), .wb_dout_pre_up (el2_mem_export.wb_dout_pre_up), .iccm_ecc_single_error (), .iccm_ecc_double_error (), .dccm_ecc_single_error (), .dccm_ecc_double_error (), `ifdef RV_LOCKSTEP_ENABLE .disable_corruption_detection_i ('0), .lockstep_err_injection_en_i ('0), .corruption_detected_o (), `endif .soft_int (soft_int), .core_id ('0), .scan_mode ( 1'b0 ), // To enable scan mode .mbist_mode ( 1'b0 ), // to enable mbist .dmi_core_enable (dmi_core_enable), .dmi_uncore_enable (), .dmi_uncore_en (), .dmi_uncore_wr_en (), .dmi_uncore_addr (), .dmi_uncore_wdata (), .dmi_uncore_rdata (), .dmi_active () ); //=========================================================================- // AHB I$ instance //=========================================================================- `ifdef RV_BUILD_AHB_LITE ahb_sif imem ( // Inputs .HWDATA(64'h0), .HCLK(core_clk), .HSEL(1'b1), .HPROT(ic_hprot), .HWRITE(ic_hwrite), .HTRANS(ic_htrans), .HSIZE(ic_hsize), .HREADY(ic_hready), .HRESETn(rst_l), .HADDR(ic_haddr), .HBURST(ic_hburst), // Outputs .HREADYOUT(ic_hready), .HRESP(ic_hresp), .HRDATA(ic_hrdata[63:0]) ); ahb_sif #( .MAX_DELAY(1), .MIN_DELAY(1) )lmem( // Inputs .HCLK(core_clk), .HRESETn(rst_l), .HSEL(lmem_hsel), .HADDR(lmem_haddr), .HBURST(lmem_hburst), .HPROT(lmem_hprot), .HWRITE(lmem_hwrite), .HWDATA(lmem_hwdata), .HTRANS(lmem_htrans), .HSIZE(lmem_hsize), .HREADY(lmem_hready_out), // Outputs .HREADYOUT(lmem_hready_out), .HRESP(lmem_hresp), .HRDATA(lmem_hrdata) ); ahb_lsu_dma_bridge #(.pt(pt)) bridge ( .clk(core_clk), .reset_l(rst_l), .m_ahb_haddr(mux_haddr[31:0]), .m_ahb_hburst(mux_hburst), .m_ahb_hmastlock(mux_hmastlock), .m_ahb_hprot(mux_hprot[3:0]), .m_ahb_hsize(mux_hsize[2:0]), .m_ahb_htrans(mux_htrans[1:0]), .m_ahb_hwrite(mux_hwrite), .m_ahb_hwdata(mux_hwdata[63:0]), .m_ahb_hsel(mux_hsel), .m_ahb_hreadyin(mux_hready), .m_ahb_hrdata(mux_hrdata[63:0]), .m_ahb_hreadyout(mux_hreadyout), .m_ahb_hresp(mux_hresp), .s0_ahb_hsel(lmem_hsel), .s0_ahb_haddr(lmem_haddr), .s0_ahb_hburst(lmem_hburst), .s0_ahb_hmastlock(lmem_hmastlock), .s0_ahb_hprot(lmem_hprot), .s0_ahb_hsize(lmem_hsize), .s0_ahb_htrans(lmem_htrans), .s0_ahb_hwrite(lmem_hwrite), .s0_ahb_hwdata(lmem_hwdata), .s0_ahb_hrdata(lmem_hrdata), .s0_ahb_hready(lmem_hready_out), .s0_ahb_hresp(lmem_hresp), .s1_ahb_hsel(dma_hsel), .s1_ahb_haddr(dma_haddr), .s1_ahb_hburst(dma_hburst), .s1_ahb_hmastlock(dma_hmastlock), .s1_ahb_hprot(dma_hprot), .s1_ahb_hsize(dma_hsize), .s1_ahb_htrans(dma_htrans), .s1_ahb_hwrite(dma_hwrite), .s1_ahb_hwdata(dma_hwdata), .s1_ahb_hrdata(dma_hrdata), .s1_ahb_hready(dma_hready_out), .s1_ahb_hresp(dma_hresp) ); `endif // RV_BUILD_AHB_LITE `ifdef RV_BUILD_AXI4 axi_slv #(.TAGW(`RV_IFU_BUS_TAG)) imem( .aclk(core_clk), .rst_l(rst_l), .arvalid(ifu_axi_arvalid), .arready(ifu_axi_arready), .araddr(ifu_axi_araddr), .arid(ifu_axi_arid), .arlen(ifu_axi_arlen), .arburst(ifu_axi_arburst), .arsize(ifu_axi_arsize), .rvalid(ifu_axi_rvalid), .rready(ifu_axi_rready), .rdata(ifu_axi_rdata), .rresp(ifu_axi_rresp), .rid(ifu_axi_rid), .rlast(ifu_axi_rlast), .awvalid(1'b0), .awready(), .awaddr('0), .awid('0), .awlen('0), .awburst('0), .awsize('0), .wdata('0), .wstrb('0), .wvalid(1'b0), .wready(), .bvalid(), .bready(1'b0), .bresp(), .bid() ); defparam lmem.TAGW = RV_MUX_BUS_TAG; //axi_slv #(.TAGW(`RV_LSU_BUS_TAG)) lmem( axi_slv lmem( .aclk(core_clk), .rst_l(rst_l), .arvalid(lmem_axi_arvalid), .arready(lmem_axi_arready), .araddr(mux_axi_araddr), .arid(mux_axi_arid), .arlen(mux_axi_arlen), .arburst(mux_axi_arburst), .arsize(mux_axi_arsize), .rvalid(lmem_axi_rvalid), .rready(lmem_axi_rready), .rdata(lmem_axi_rdata), .rresp(lmem_axi_rresp), .rid(lmem_axi_rid), .rlast(lmem_axi_rlast), .awvalid(lmem_axi_awvalid), .awready(lmem_axi_awready), .awaddr(mux_axi_awaddr), .awid(mux_axi_awid), .awlen(mux_axi_awlen), .awburst(mux_axi_awburst), .awsize(mux_axi_awsize), .wdata(mux_axi_wdata), .wstrb(mux_axi_wstrb), .wvalid(lmem_axi_wvalid), .wready(lmem_axi_wready), .bvalid(lmem_axi_bvalid), .bready(lmem_axi_bready), .bresp(lmem_axi_bresp), .bid(lmem_axi_bid) ); axi_lsu_dma_bridge # (RV_MUX_BUS_TAG, RV_MUX_BUS_TAG) bridge( .clk(core_clk), .reset_l(rst_l), .m_arvalid(mux_axi_arvalid), .m_arid(mux_axi_arid), .m_araddr(mux_axi_araddr), .m_arready(mux_axi_arready), .m_rvalid(mux_axi_rvalid), .m_rready(mux_axi_rready), .m_rdata(mux_axi_rdata), .m_rid(mux_axi_rid), .m_rresp(mux_axi_rresp), .m_rlast(mux_axi_rlast), .m_awvalid(mux_axi_awvalid), .m_awid(mux_axi_awid), .m_awaddr(mux_axi_awaddr), .m_awready(mux_axi_awready), .m_wvalid(mux_axi_wvalid), .m_wready(mux_axi_wready), .m_bresp(mux_axi_bresp), .m_bvalid(mux_axi_bvalid), .m_bid(mux_axi_bid), .m_bready(mux_axi_bready), .s0_arvalid(lmem_axi_arvalid), .s0_arready(lmem_axi_arready), .s0_rvalid(lmem_axi_rvalid), .s0_rid(lmem_axi_rid), .s0_rresp(lmem_axi_rresp), .s0_rdata(lmem_axi_rdata), .s0_rlast(lmem_axi_rlast), .s0_rready(lmem_axi_rready), .s0_awvalid(lmem_axi_awvalid), .s0_awready(lmem_axi_awready), .s0_wvalid(lmem_axi_wvalid), .s0_wready(lmem_axi_wready), .s0_bresp(lmem_axi_bresp), .s0_bvalid(lmem_axi_bvalid), .s0_bid(lmem_axi_bid), .s0_bready(lmem_axi_bready), .s1_arvalid(dma_axi_arvalid), .s1_arready(dma_axi_arready), .s1_rvalid(dma_axi_rvalid), .s1_rresp(dma_axi_rresp), .s1_rdata(dma_axi_rdata), .s1_rlast(dma_axi_rlast), .s1_rready(dma_axi_rready), .s1_awvalid(dma_axi_awvalid), .s1_awready(dma_axi_awready), .s1_wvalid(dma_axi_wvalid), .s1_wready(dma_axi_wready), .s1_bresp(dma_axi_bresp), .s1_bvalid(dma_axi_bvalid), .s1_bready(dma_axi_bready) ); `endif task preload_iccm; bit[31:0] data; bit[31:0] addr, eaddr, saddr; /* addresses: 0xfffffff0 - ICCM start address to load 0xfffffff4 - ICCM end address to load */ `ifndef VERILATOR init_iccm(); `endif addr = 'hffff_fff0; saddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; if ( (saddr < `RV_ICCM_SADR) || (saddr > `RV_ICCM_EADR)) return; `ifndef RV_ICCM_ENABLE $display("********************************************************"); $display("ICCM preload: there is no ICCM in VeeR, terminating !!!"); $display("********************************************************"); $finish; `endif addr += 4; eaddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; $display("ICCM pre-load from %h to %h", saddr, eaddr); for(addr= saddr; addr <= eaddr; addr+=4) begin data = {imem.mem[addr+3],imem.mem[addr+2],imem.mem[addr+1],imem.mem[addr]}; slam_iccm_ram(addr, data == 0 ? 0 : {riscv_ecc32(data),data}); end endtask task preload_dccm; bit[31:0] data; bit[31:0] addr, saddr, eaddr; /* addresses: 0xffff_fff8 - DCCM start address to load 0xffff_fffc - DCCM end address to load */ addr = 'hffff_fff8; saddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; if (saddr < `RV_DCCM_SADR || saddr > `RV_DCCM_EADR) return; `ifndef RV_DCCM_ENABLE $display("********************************************************"); $display("DCCM preload: there is no DCCM in VeeR, terminating !!!"); $display("********************************************************"); $finish; `endif addr += 4; eaddr = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; $display("DCCM pre-load from %h to %h", saddr, eaddr); for(addr=saddr; addr <= eaddr; addr+=4) begin data = {lmem.mem[addr+3],lmem.mem[addr+2],lmem.mem[addr+1],lmem.mem[addr]}; slam_dccm_ram(addr, data == 0 ? 0 : {riscv_ecc32(data),data}); end endtask `define DRAM(bk) Gen_dccm_enable.dccm_loop[bk].dccm.dccm_bank.ram_core `define IRAM(bk) Gen_iccm_enable.iccm_loop[bk].iccm.iccm_bank.ram_core task slam_dccm_ram(input [31:0] addr, input[38:0] data); int bank, indx; bank = get_dccm_bank(addr, indx); `ifdef RV_DCCM_ENABLE case(bank) 0: `DRAM(0)[indx] = data; 1: `DRAM(1)[indx] = data; `ifdef RV_DCCM_NUM_BANKS_4 2: `DRAM(2)[indx] = data; 3: `DRAM(3)[indx] = data; `endif `ifdef RV_DCCM_NUM_BANKS_8 2: `DRAM(2)[indx] = data; 3: `DRAM(3)[indx] = data; 4: `DRAM(4)[indx] = data; 5: `DRAM(5)[indx] = data; 6: `DRAM(6)[indx] = data; 7: `DRAM(7)[indx] = data; `endif endcase `endif //$display("Writing bank %0d indx=%0d A=%h, D=%h",bank, indx, addr, data); endtask task slam_iccm_ram( input[31:0] addr, input[38:0] data); int bank, idx; bank = get_iccm_bank(addr, idx); `ifdef RV_ICCM_ENABLE case(bank) // { 0: `IRAM(0)[idx] = data; 1: `IRAM(1)[idx] = data; `ifdef RV_ICCM_NUM_BANKS_4 2: `IRAM(2)[idx] = data; 3: `IRAM(3)[idx] = data; `endif `ifdef RV_ICCM_NUM_BANKS_8 2: `IRAM(2)[idx] = data; 3: `IRAM(3)[idx] = data; 4: `IRAM(4)[idx] = data; 5: `IRAM(5)[idx] = data; 6: `IRAM(6)[idx] = data; 7: `IRAM(7)[idx] = data; `endif `ifdef RV_ICCM_NUM_BANKS_16 2: `IRAM(2)[idx] = data; 3: `IRAM(3)[idx] = data; 4: `IRAM(4)[idx] = data; 5: `IRAM(5)[idx] = data; 6: `IRAM(6)[idx] = data; 7: `IRAM(7)[idx] = data; 8: `IRAM(8)[idx] = data; 9: `IRAM(9)[idx] = data; 10: `IRAM(10)[idx] = data; 11: `IRAM(11)[idx] = data; 12: `IRAM(12)[idx] = data; 13: `IRAM(13)[idx] = data; 14: `IRAM(14)[idx] = data; 15: `IRAM(15)[idx] = data; `endif endcase // } `endif endtask task init_iccm; `ifdef RV_ICCM_ENABLE `IRAM(0) = '{default:39'h0}; `IRAM(1) = '{default:39'h0}; `ifdef RV_ICCM_NUM_BANKS_4 `IRAM(2) = '{default:39'h0}; `IRAM(3) = '{default:39'h0}; `endif `ifdef RV_ICCM_NUM_BANKS_8 `IRAM(4) = '{default:39'h0}; `IRAM(5) = '{default:39'h0}; `IRAM(6) = '{default:39'h0}; `IRAM(7) = '{default:39'h0}; `endif `ifdef RV_ICCM_NUM_BANKS_16 `IRAM(4) = '{default:39'h0}; `IRAM(5) = '{default:39'h0}; `IRAM(6) = '{default:39'h0}; `IRAM(7) = '{default:39'h0}; `IRAM(8) = '{default:39'h0}; `IRAM(9) = '{default:39'h0}; `IRAM(10) = '{default:39'h0}; `IRAM(11) = '{default:39'h0}; `IRAM(12) = '{default:39'h0}; `IRAM(13) = '{default:39'h0}; `IRAM(14) = '{default:39'h0}; `IRAM(15) = '{default:39'h0}; `endif `endif endtask function[6:0] riscv_ecc32(input[31:0] data); reg[6:0] synd; synd[0] = ^(data & 32'h56aa_ad5b); synd[1] = ^(data & 32'h9b33_366d); synd[2] = ^(data & 32'he3c3_c78e); synd[3] = ^(data & 32'h03fc_07f0); synd[4] = ^(data & 32'h03ff_f800); synd[5] = ^(data & 32'hfc00_0000); synd[6] = ^{data, synd[5:0]}; return synd; endfunction function int get_dccm_bank(input[31:0] addr, output int bank_idx); `ifdef RV_DCCM_NUM_BANKS_2 bank_idx = int'(addr[`RV_DCCM_BITS-1:3]); return int'( addr[2]); `elsif RV_DCCM_NUM_BANKS_4 bank_idx = int'(addr[`RV_DCCM_BITS-1:4]); return int'(addr[3:2]); `elsif RV_DCCM_NUM_BANKS_8 bank_idx = int'(addr[`RV_DCCM_BITS-1:5]); return int'( addr[4:2]); `endif endfunction function int get_iccm_bank(input[31:0] addr, output int bank_idx); `ifdef RV_DCCM_NUM_BANKS_2 bank_idx = int'(addr[`RV_DCCM_BITS-1:3]); return int'( addr[2]); `elsif RV_ICCM_NUM_BANKS_4 bank_idx = int'(addr[`RV_ICCM_BITS-1:4]); return int'(addr[3:2]); `elsif RV_ICCM_NUM_BANKS_8 bank_idx = int'(addr[`RV_ICCM_BITS-1:5]); return int'( addr[4:2]); `elsif RV_ICCM_NUM_BANKS_16 bank_idx = int'(addr[`RV_ICCM_BITS-1:6]); return int'( addr[5:2]); `endif endfunction task dump_signature (); integer fp, i; $display("Dumping memory signature (0x%08X - 0x%08X)...", mem_signature_begin, mem_signature_end ); fp = $fopen("veer.signature", "w"); for (i=mem_signature_begin; i= `RV_DCCM_SADR && i < `RV_DCCM_EADR) begin bit[38:0] data; int bank, indx; bank = get_dccm_bank(i, indx); case (bank) 0: data = `DRAM(0)[indx]; 1: data = `DRAM(1)[indx]; `ifdef RV_DCCM_NUM_BANKS_4 2: data = `DRAM(2)[indx]; 3: data = `DRAM(3)[indx]; `endif `ifdef RV_DCCM_NUM_BANKS_8 2: data = `DRAM(2)[indx]; 3: data = `DRAM(3)[indx]; 4: data = `DRAM(4)[indx]; 5: data = `DRAM(5)[indx]; 6: data = `DRAM(6)[indx]; 7: data = `DRAM(7)[indx]; `endif endcase $fwrite(fp, "%08X\n", data[31:0]); end else `endif // From RAM begin $fwrite(fp, "%02X%02X%02X%02X\n", lmem.mem[i+3], lmem.mem[i+2], lmem.mem[i+1], lmem.mem[i+0] ); end end $fclose(fp); endtask ////////////////////////////////////////////////////// // DCCM // if (pt.DCCM_ENABLE == 1) begin: Gen_dccm_enable `define EL2_LOCAL_DCCM_RAM_TEST_PORTS .TEST1 (1'b0 ), \ .RME (1'b0 ), \ .RM (4'b0000), \ .LS (1'b0 ), \ .DS (1'b0 ), \ .SD (1'b0 ), \ .TEST_RNM(1'b0 ), \ .BC1 (1'b0 ), \ .BC2 (1'b0 ), \ logic [pt.DCCM_NUM_BANKS-1:0] [pt.DCCM_FDATA_WIDTH-1:0] dccm_wdata_bitflip; int ii; localparam DCCM_INDEX_DEPTH = ((pt.DCCM_SIZE)*1024)/((pt.DCCM_BYTE_WIDTH)*(pt.DCCM_NUM_BANKS)); // Depth of memory bank // 8 Banks, 16KB each (2048 x 72) always_ff @(el2_mem_export.clk) begin : inject_dccm_ecc_error if (~error_injection_mode.dccm_single_bit_error && ~error_injection_mode.dccm_double_bit_error) begin dccm_wdata_bitflip <= '{default:0}; end else if (el2_mem_export.dccm_clken & el2_mem_export.dccm_wren_bank) begin for (ii=0; ii // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 #include "tcp_server.h" #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Simple buffer for passing data between TCP sockets and DPI modules */ #define BUFSIZE_BYTE 1024 // FIXME: This must be larger than the remote_bitbang // buffer in OpenOCD. Otherwise deadlock occurs. struct tcp_buf { unsigned int rptr; unsigned int wptr; char buf[BUFSIZE_BYTE]; }; /** * TCP Server thread context structure */ struct tcp_server_ctx { // Writeable by the host thread char *display_name; uint16_t listen_port; volatile bool socket_run; // Writeable by the server thread struct tcp_buf *buf_in; struct tcp_buf *buf_out; int sfd; // socket fd int cfd; // client fd pthread_t sock_thread; }; static bool tcp_buffer_is_full(struct tcp_buf *buf) { if (buf->wptr >= buf->rptr) { return (buf->wptr - buf->rptr) == (BUFSIZE_BYTE - 1); } else { return (buf->rptr - buf->wptr) == 1; } } static bool tcp_buffer_is_empty(struct tcp_buf *buf) { return (buf->wptr == buf->rptr); } static void tcp_buffer_put_byte(struct tcp_buf *buf, char dat) { bool done = false; while (!done) { if (!tcp_buffer_is_full(buf)) { buf->buf[buf->wptr++] = dat; buf->wptr %= BUFSIZE_BYTE; done = true; } } } static bool tcp_buffer_get_byte(struct tcp_buf *buf, char *dat) { if (tcp_buffer_is_empty(buf)) { return false; } *dat = buf->buf[buf->rptr++]; buf->rptr %= BUFSIZE_BYTE; return true; } static struct tcp_buf *tcp_buffer_new(void) { struct tcp_buf *buf_new; buf_new = (struct tcp_buf *)malloc(sizeof(struct tcp_buf)); buf_new->rptr = 0; buf_new->wptr = 0; return buf_new; } static void tcp_buffer_free(struct tcp_buf **buf) { free(*buf); *buf = NULL; } /** * Start a TCP server * * This function creates attempts to create a new TCP socket instance. The * socket is a non-blocking stream socket, with buffering disabled. * * @param ctx context object * @return 0 on success, -1 in case of an error */ static int start(struct tcp_server_ctx *ctx) { int rv; assert(ctx->sfd == 0 && "Server already started."); // create socket int sfd = socket(AF_INET, SOCK_STREAM, 0); if (sfd == -1) { fprintf(stderr, "%s: Unable to create socket: %s (%d)\n", ctx->display_name, strerror(errno), errno); return -1; } rv = fcntl(sfd, F_SETFL, O_NONBLOCK); if (rv != 0) { fprintf(stderr, "%s: Unable to make socket non-blocking: %s (%d)\n", ctx->display_name, strerror(errno), errno); return -1; } // reuse existing socket (if existing) int reuse_socket = 1; rv = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)); if (rv != 0) { fprintf(stderr, "%s: Unable to set socket options: %s (%d)\n", ctx->display_name, strerror(errno), errno); return -1; } // stop tcp socket from buffering (buffering prevents timely responses to // OpenOCD which severly limits debugging performance) int tcp_nodelay = 1; rv = setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &tcp_nodelay, sizeof(int)); if (rv != 0) { fprintf(stderr, "%s: Unable to set socket nodelay: %s (%d)\n", ctx->display_name, strerror(errno), errno); return -1; } // bind server struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(ctx->listen_port); rv = bind(sfd, (struct sockaddr *)&addr, sizeof(addr)); if (rv != 0) { fprintf(stderr, "%s: Failed to bind socket: %s (%d)\n", ctx->display_name, strerror(errno), errno); return -1; } // listen for incoming connections rv = listen(sfd, 1); if (rv != 0) { fprintf(stderr, "%s: Failed to listen on socket: %s (%d)\n", ctx->display_name, strerror(errno), errno); return -1; } ctx->sfd = sfd; assert(ctx->sfd > 0); return 0; } /** * Accept an incoming connection from a client (nonblocking) * * The resulting client fd is made non-blocking. * * @param ctx context object * @return 0 on success, any other value indicates an error */ static int client_tryaccept(struct tcp_server_ctx *ctx) { int rv; assert(ctx->sfd > 0); assert(ctx->cfd == 0); int cfd = accept(ctx->sfd, NULL, NULL); if (cfd == -1 && errno == EAGAIN) { return -EAGAIN; } if (cfd == -1) { fprintf(stderr, "%s: Unable to accept incoming connection: %s (%d)\n", ctx->display_name, strerror(errno), errno); return -1; } rv = fcntl(cfd, F_SETFL, O_NONBLOCK); if (rv != 0) { fprintf(stderr, "%s: Unable to make client socket non-blocking: %s (%d)\n", ctx->display_name, strerror(errno), errno); return -1; } ctx->cfd = cfd; assert(ctx->cfd > 0); printf("%s: Accepted client connection\n", ctx->display_name); return 0; } /** * Stop the TCP server * * @param ctx context object */ static void stop(struct tcp_server_ctx *ctx) { assert(ctx); if (!ctx->sfd) { return; } close(ctx->sfd); ctx->sfd = 0; } /** * Receive a byte from a connected client * * @param ctx context object * @param cmd byte received * @return true if a byte was read */ static bool get_byte(struct tcp_server_ctx *ctx, char *cmd) { assert(ctx); ssize_t num_read = read(ctx->cfd, cmd, 1); if (num_read == 0) { return false; } if (num_read == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return false; } else if (errno == EBADF) { // Possibly client went away? Accept a new connection. fprintf(stderr, "%s: Client disappeared.\n", ctx->display_name); tcp_server_client_close(ctx); return false; } else { fprintf(stderr, "%s: Error while reading from client: %s (%d)\n", ctx->display_name, strerror(errno), errno); assert(0 && "Error reading from client"); } } assert(num_read == 1); return true; } /** * Send a byte to a connected client * * @param ctx context object * @param cmd byte to send */ static void put_byte(struct tcp_server_ctx *ctx, char cmd) { while (1) { ssize_t num_written = send(ctx->cfd, &cmd, sizeof(cmd), MSG_NOSIGNAL); if (num_written == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { continue; } else if (errno == EPIPE) { printf("%s: Remote disconnected.\n", ctx->display_name); tcp_server_client_close(ctx); break; } else { fprintf(stderr, "%s: Error while writing to client: %s (%d)\n", ctx->display_name, strerror(errno), errno); assert(0 && "Error writing to client."); } } if (num_written >= 1) { break; } } } /** * Cleanup server context * * @param ctx context object */ static void ctx_free(struct tcp_server_ctx *ctx) { // Free the buffers tcp_buffer_free(&ctx->buf_in); tcp_buffer_free(&ctx->buf_out); // Free the display name free(ctx->display_name); // Free the ctx free(ctx); ctx = NULL; } /** * Thread function to create a new server instance * * @param ctx_void context object * @return Always returns NULL */ static void *server_create(void *ctx_void) { // Cast to a server struct struct tcp_server_ctx *ctx = (struct tcp_server_ctx *)ctx_void; struct timeval timeout; // Start the server int rv = start(ctx); if (rv != 0) { fprintf(stderr, "%s: Unable to create TCP server on port %d\n", ctx->display_name, ctx->listen_port); goto err_cleanup_return; } // Initialise timeout timeout.tv_sec = 0; // Initialise fd_set // Start waiting for connection / data char xfer_data; while (ctx->socket_run) { // Initialise structure of fds fd_set read_fds; FD_ZERO(&read_fds); if (ctx->sfd) { FD_SET(ctx->sfd, &read_fds); } if (ctx->cfd) { FD_SET(ctx->cfd, &read_fds); } // max fd num int mfd = (ctx->cfd > ctx->sfd) ? ctx->cfd : ctx->sfd; // Set timeout - 50us gives good performance timeout.tv_usec = 50; // Wait for socket activity or timeout rv = select(mfd + 1, &read_fds, NULL, NULL, &timeout); if (rv < 0) { printf("%s: Socket read failed, port: %d\n", ctx->display_name, ctx->listen_port); tcp_server_client_close(ctx); } // New connection if (FD_ISSET(ctx->sfd, &read_fds)) { client_tryaccept(ctx); } // New client data if (FD_ISSET(ctx->cfd, &read_fds)) { while (get_byte(ctx, &xfer_data)) { tcp_buffer_put_byte(ctx->buf_in, xfer_data); } } if (ctx->cfd != 0) { while (tcp_buffer_get_byte(ctx->buf_out, &xfer_data)) { put_byte(ctx, xfer_data); } } } err_cleanup_return: // Simulation done - clean up tcp_server_client_close(ctx); stop(ctx); return NULL; } // Abstract interface functions struct tcp_server_ctx *tcp_server_create(const char *display_name, int listen_port) { struct tcp_server_ctx *ctx = (struct tcp_server_ctx *)calloc(1, sizeof(struct tcp_server_ctx)); assert(ctx); // Create the buffers struct tcp_buf *buf_in = tcp_buffer_new(); struct tcp_buf *buf_out = tcp_buffer_new(); assert(buf_in); assert(buf_out); // Populate the struct with buffer pointers ctx->buf_in = buf_in; ctx->buf_out = buf_out; // Set up socket details ctx->socket_run = true; ctx->listen_port = listen_port; ctx->display_name = strdup(display_name); assert(ctx->display_name); if (pthread_create(&ctx->sock_thread, NULL, server_create, (void *)ctx) != 0) { fprintf(stderr, "%s: Unable to create TCP socket thread\n", ctx->display_name); ctx_free(ctx); free(ctx); return NULL; } return ctx; } bool tcp_server_read(struct tcp_server_ctx *ctx, char *dat) { return tcp_buffer_get_byte(ctx->buf_in, dat); } void tcp_server_write(struct tcp_server_ctx *ctx, char dat) { tcp_buffer_put_byte(ctx->buf_out, dat); } void tcp_server_close(struct tcp_server_ctx *ctx) { // Shut down the socket thread ctx->socket_run = false; pthread_join(ctx->sock_thread, NULL); ctx_free(ctx); } void tcp_server_client_close(struct tcp_server_ctx *ctx) { assert(ctx); if (!ctx->cfd) { return; } close(ctx->cfd); ctx->cfd = 0; } ================================================ FILE: testbench/tcp_server/tcp_server.h ================================================ // Copyright lowRISC contributors. // Copyright 2024 Antmicro // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 #ifndef OPENTITAN_HW_DV_DPI_COMMON_TCP_SERVER_TCP_SERVER_H_ #define OPENTITAN_HW_DV_DPI_COMMON_TCP_SERVER_TCP_SERVER_H_ /** * Functions to create and interact with a threaded TCP server * * This is intended to be used by simulation add-on DPI modules to provide * basic TCP socket communication between a host and simulated peripherals. */ #ifdef __cplusplus extern "C" { #endif #include #include struct tcp_server_ctx; /** * Non-blocking read of a byte from a connected client * * @param ctx tcp server context object * @param dat byte received * @return true if a byte was read */ bool tcp_server_read(struct tcp_server_ctx *ctx, char *dat); /** * Write a byte to a connected client * * The write is internally buffered and so does not block if the client is not * ready to accept data, but does block if the buffer is full. * * @param ctx tcp server context object * @param dat byte to send */ void tcp_server_write(struct tcp_server_ctx *ctx, char dat); /** * Create a new TCP server instance * * @param display_name C string description of server * @param listen_port On which port the server should listen * @return A pointer to the created context struct */ struct tcp_server_ctx *tcp_server_create(const char *display_name, int listen_port); /** * Shut down the server and free all reserved memory * * @param ctx tcp server context object */ void tcp_server_close(struct tcp_server_ctx *ctx); /** * Instruct the server to disconnect a client * * @param ctx tcp server context object */ void tcp_server_client_close(struct tcp_server_ctx *ctx); #ifdef __cplusplus } // extern "C" #endif #endif // OPENTITAN_HW_DV_DPI_COMMON_TCP_SERVER_TCP_SERVER_H_ ================================================ FILE: testbench/test_tb_top.cpp ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2019 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include #include #include #include #include #include #include "Vtb_top.h" #include "verilated.h" #include "verilated_vcd_c.h" vluint64_t main_time = 0; double sc_time_stamp () { return main_time; } std::map load_symbols (const std::string& fileName) { // Open the symbol list file std::ifstream fp(fileName); if (!fp.good()) { std::cerr << "Error loading symbols from '" << fileName << "'" << std::endl; exit(EXIT_FAILURE); } // Parse lines std::map symbols; for (std::string line; std::getline(fp, line); ) { // Remove any trailing whitespaces auto pos = line.find_last_not_of(" \r\n\t"); line = line.substr(0, pos + 1); // Get address auto apos = line.find_first_of(" \r\n\t"); const auto astr = line.substr(0, apos); // Get name auto npos = line.find_last_of(" \r\n\t"); const auto nstr = line.substr(npos + 1); symbols[nstr] = strtol(astr.c_str(), nullptr, 16); } return symbols; } int main(int argc, char** argv) { std::cout << "\nVerilatorTB: Start of sim\n" << std::endl; Verilated::commandArgs(argc, argv); Vtb_top* tb = new Vtb_top; bool test_halt = false; bool test_lsu_clk_ratio = false; tb->mem_signature_begin = 0x00000000; tb->mem_signature_end = 0x00000000; tb->mem_mailbox = 0xD0580000; std::map symbols; // Setup memory signature range by looking up symbol names in the provided // symbol dump file for (int i=1; imem_signature_begin = beg->second; tb->mem_signature_end = end->second; } } } // Setup memory signature range if provided. Look for the commandline option // "--mem-signature ". Addresses need to be hexadecimal for (int i=1; imem_signature_begin = strtol(argv[i+1], nullptr, 16); tb->mem_signature_end = strtol(argv[i+2], nullptr, 16); } } // Set mailbox address if provided. The commandline option is: // "--mailbox-addr
" for (int i=1; imem_mailbox = strtol(argv[i+1], nullptr, 16); } } // Set mailbox address to the address of the given symbol name via: // "--mailbox-sym " for (int i=1; imem_mailbox = it->second; } } } // run halt start procedure if requested with // "--test-halt" for (int i=1; ilsu_bus_clk_en = 1; // reset tb->rst_l = 0; for (int i=0;i<6;i++) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } tb->rst_l = 1; // Simulate if(test_halt) { // Test halt/start first (if requested) tb->i_cpu_halt_req = 1; // wait for ack std::cout<<"Waiting for halt"<o_cpu_halt_ack) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } tb->i_cpu_halt_req = 0; // wait for halt signal while(!tb->o_cpu_halt_status) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } // restart the CPU tb->i_cpu_run_req = 1; // wait for ack while(!tb->o_cpu_run_ack) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } tb->i_cpu_run_req = 0; // wait for run signal std::cout<<"Waiting for restart"<o_cpu_halt_status) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } // test mpc halt tb->mpc_debug_halt_req = 1; // wait for ack std::cout<<"Waiting for mpc halt"<mpc_debug_halt_ack) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } tb->mpc_debug_halt_req = 0; // wait for halt signal while(!tb->o_debug_mode_status) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } // restart the CPU tb->mpc_debug_run_req = 1; // wait for ack while(!tb->mpc_debug_run_ack) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } tb->mpc_debug_run_req = 0; // wait for run signal std::cout<<"Waiting for mpc restart"<o_debug_mode_status) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } } else { tb->i_cpu_halt_req = 0; tb->i_cpu_run_req = 0; tb->mpc_debug_halt_req = 0; tb->mpc_debug_run_req = 0; } if (test_lsu_clk_ratio) { std::cout<<"Test lower clock ratio between bus master interface and core" << std::endl; tb->lsu_bus_clk_en = 0; for(int i=0;i<30;i++) { for(int j=0;j<10;j++) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } tb->lsu_bus_clk_en = !tb->lsu_bus_clk_en; } tb->lsu_bus_clk_en = 1; std::cout<<"Pre-start checks complete. Restarting again for normal operation." << std::endl; // reset tb->rst_l = 0; for (int i=0;i<30;i++) { main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } tb->rst_l = 1; } while(!Verilated::gotFinish()){ #if VM_TRACE tfp->dump (main_time); #endif main_time += 5; tb->core_clk = !tb->core_clk; tb->eval(); } tb->final(); #if VM_TRACE tfp->close(); #endif // Write coverage data #if VM_COVERAGE Verilated::threadContextp()->coveragep()->write("coverage.dat"); #endif std::cout << "\nVerilatorTB: End of sim" << std::endl; exit(EXIT_SUCCESS); } ================================================ FILE: testbench/tests/clk_override/clk_override.c ================================================ #include #include int main () { uint32_t value = 0; __asm__ volatile ( "csrw 0x7f8, %0" // Write the value of foo to MCGC CSR : // No output operands : "r"(value) // Input operand (value) as register ); for (int bit = 0; bit <= 9; bit++) { value = 1 << bit; __asm__ volatile ( "csrw 0x7f8, %0" : : "r"(value) ); } return 0; } ================================================ FILE: testbench/tests/clk_override/clk_override.ld ================================================ /* SPDX-License-Identifier: Apache-2.0 */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text.init*) *(.text*) } _end = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/tests/clk_override/clk_override.mki ================================================ # SPDX-License-Identifier: Apache-2.0 OFILES = crt0.o clk_override.o printf.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/tests/clk_override/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .section .text.init .global _start _start: # Setup stack la sp, STACK # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/core_pause/core_pause.c ================================================ #include #include int main () { /* pause the core for 0xfff cycles */ uint32_t value = 0xfff; __asm__ volatile ( "csrw 0x7c2, %0" // Write the value of foo to MCPC CSR : // No output operands : "r"(value) // Input operand (value) as register ); return 0; } ================================================ FILE: testbench/tests/core_pause/core_pause.ld ================================================ /* SPDX-License-Identifier: Apache-2.0 */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text.init*) *(.text*) } _end = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/tests/core_pause/core_pause.mki ================================================ # SPDX-License-Identifier: Apache-2.0 OFILES = crt0.o core_pause.o printf.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/tests/core_pause/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .section .text.init .global _start _start: # Setup stack la sp, STACK # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/csr_access/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .section .text.init .global _start _start: # Setup stack la sp, STACK # Setup trap handler la t0, _trap csrw mtvec, t0 # Setup PMP # Region 0 TOR 0x00000000-0xFFFFFFFF RWX li t0, 0xFFFFFFFF csrw pmpaddr0, t0 li t0, 0x0000000F csrw pmpcfg0, t0 # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr _trap: # Push stuff addi sp, sp, -17*4 sw ra, 0*4(sp) sw a0, 1*4(sp) sw a1, 2*4(sp) sw a2, 3*4(sp) sw a3, 4*4(sp) sw a4, 5*4(sp) sw a5, 6*4(sp) sw a6, 7*4(sp) sw a7, 8*4(sp) sw t0, 9*4(sp) sw t1, 10*4(sp) sw t2, 11*4(sp) sw t3, 12*4(sp) sw t4, 13*4(sp) sw t5, 14*4(sp) sw t6, 15*4(sp) call trap_handler # Advance mepc if the cause is not an external interrupt csrr t0, mcause li t1, 0x80000000 and t0, t0, t1 bne t0, x0, _is_irq csrr t0, mepc addi t0, t0, 4 csrw mepc, t0 _is_irq: # Pop stuff lw ra, 0*4(sp) lw a0, 1*4(sp) lw a1, 2*4(sp) lw a2, 3*4(sp) lw a3, 4*4(sp) lw a4, 5*4(sp) lw a5, 6*4(sp) lw a6, 7*4(sp) lw a7, 8*4(sp) lw t0, 9*4(sp) lw t1, 10*4(sp) lw t2, 11*4(sp) lw t3, 12*4(sp) lw t4, 13*4(sp) lw t5, 14*4(sp) lw t6, 15*4(sp) addi sp, sp, 17*4 mret .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/csr_access/csr_access.c ================================================ #include #include #include #define _read_csr(csr) ({ \ unsigned long res; \ asm volatile ("csrr %0, " #csr : "=r"(res)); \ res; \ }) #define _write_csr(csr, val) { \ asm volatile ("csrw " #csr ", %0" : : "r"(val)); \ } #define MISA_U (1 << 20) #define MAGIC 0xDEADBEEF struct csr_t { uint32_t addr; const char* name; }; static const struct csr_t g_read_csrs[] = { {0xF11, "mvendorid"}, {0xF12, "marchid"}, {0xF13, "mimpid"}, {0xF14, "mhartid"}, {0x300, "mstatus"}, {0x301, "misa"}, {0x304, "mie"}, {0x305, "mtvec"}, {0x306, "mcounteren"}, {0x320, "mcountinhibit"}, {0x340, "mscratch"}, {0x341, "mepc"}, {0x342, "mcause"}, {0x343, "mtval"}, {0x344, "mip"}, {0xB00, "mcycle"}, {0xB02, "minstret"}, {0xB80, "mcycleh"}, {0xB82, "minstreth"}, {0x30A, "menvcfg"}, {0x31A, "menvcfgh"}, {0x747, "mseccfg"}, {0x757, "mseccfgh"}, // PMP {0x3A0, "pmpcfg0"}, {0x3B0, "pmpaddr0"}, {0x3C0, "pmpaddr16"}, {0x3D0, "pmpaddr32"}, {0x3E0, "pmpaddr48"}, {0xC00, "cycle"}, {0xC80, "cycleh"}, {0xC02, "instret"}, {0xC82, "instreth"}, // VeeR specific CSRs {0x7FF, "mscause"}, {0xBC0, "mdeau"}, {0xFC0, "mdseac"}, {0xBC8, "meivt"}, {0xFC8, "meihap"}, {0xBC9, "meipt"}, // {0xBCA, "meicpct"}, // This one seems to be readable only when an interrupt is pending {0xBCC, "meicurpl"}, {0xBCB, "meicidpl"}, // {0x7B0, "dcsr"}, // These are accessible only when the core is halted // {0x7B1, "dpc"}, // {0x7C4, "dmst"}, // {0x7C8, "dicawics"}, // {0x7CC, "dicad0h"}, // {0x7C9, "dicad0"}, // {0x7CA, "dicad1"}, // {0x7CB, "dicago"}, {0x7A0, "mtsel"}, {0x7A1, "mtdata1"}, {0x7A2, "mtdata2"}, {0x7C0, "mrac"}, {0xB03, "mhpmc3"}, {0xB04, "mhpmc4"}, {0xB05, "mhpmc5"}, {0xB06, "mhpmc6"}, {0xB83, "mhpmc3h"}, {0xB84, "mhpmc4h"}, {0xB85, "mhpmc5h"}, {0xB86, "mhpmc6h"}, {0x323, "mhpme3"}, {0x324, "mhpme4"}, {0x325, "mhpme5"}, {0x326, "mhpme6"}, {0x7F0, "micect"}, {0x7F1, "miccmect"}, {0x7F2, "mdccmect"}, {0x7C6, "mpmc"}, {0x7F8, "mcgc"}, {0x7C2, "mcpc"}, {0x7F9, "mfdc"}, {0x7D4, "mitctl0"}, {0x7D7, "mitctl1"}, {0x7D3, "mitb0"}, {0x7D6, "mitb1"}, {0x7D2, "mitcnt0"}, {0x7D5, "mitcnt1"}, {0xB07, "perfva"}, {0xB08, "perfvb"}, {0xB10, "perfvc"}, {0xB87, "perfvd"}, {0xB88, "perfve"}, {0xB90, "perfvf"}, {0x327, "perfvg"}, {0x328, "perfvh"}, {0x330, "perfvi"}, {0x7CE, "mfdht"}, {0x7CF, "mfdhs"} }; static const struct csr_t g_write_csrs[] = { // Test write only for a few CSRs not to cause unwanted effects {0x304, "mie"}, {0x340, "mscratch"}, {0x30A, "menvcfg"}, {0x31A, "menvcfgh"}, }; unsigned long read_csr (uint32_t addr) { // Define the result to be explicitly in register a0 - the return value // by the calling convention. Preset it to a magic value so that when // a CSR access fails the value stays there. volatile register uint32_t val asm("a0") = MAGIC; // Since RISC-V does not allow indirect CSR addressing there's a big // 'switch' to handle that. switch (addr) { case 0xF11: val = _read_csr(0xF11); break; case 0xF12: val = _read_csr(0xF12); break; case 0xF13: val = _read_csr(0xF13); break; case 0xF14: val = _read_csr(0xF14); break; case 0x300: val = _read_csr(0x300); break; case 0x301: val = _read_csr(0x301); break; case 0x304: val = _read_csr(0x304); break; case 0x305: val = _read_csr(0x305); break; case 0x306: val = _read_csr(0x306); break; case 0x30A: val = _read_csr(0x30A); break; case 0x31A: val = _read_csr(0x31A); break; case 0x320: val = _read_csr(0x320); break; case 0x340: val = _read_csr(0x340); break; case 0x341: val = _read_csr(0x341); break; case 0x342: val = _read_csr(0x342); break; case 0x343: val = _read_csr(0x343); break; case 0x344: val = _read_csr(0x344); break; case 0xB00: val = _read_csr(0xB00); break; case 0xB02: val = _read_csr(0xB02); break; case 0xB80: val = _read_csr(0xB80); break; case 0xB82: val = _read_csr(0xB82); break; case 0xC00: val = _read_csr(0xC00); break; case 0xC80: val = _read_csr(0xC80); break; case 0xC02: val = _read_csr(0xC02); break; case 0xC82: val = _read_csr(0xC82); break; case 0x3A0: val = _read_csr(0x3A0); break; case 0x3B0: val = _read_csr(0x3B0); break; case 0x3C0: val = _read_csr(0x3C0); break; case 0x3D0: val = _read_csr(0x3D0); break; case 0x3E0: val = _read_csr(0x3E0); break; case 0x747: val = _read_csr(0x747); break; case 0x757: val = _read_csr(0x757); break; case 0x7FF: val = _read_csr(0x7FF); break; case 0x7C0: val = _read_csr(0x7C0); break; case 0x7C4: val = _read_csr(0x7C4); break; case 0xBC0: val = _read_csr(0xBC0); break; case 0xFC0: val = _read_csr(0xFC0); break; case 0xBC8: val = _read_csr(0xBC8); break; case 0xFC8: val = _read_csr(0xFC8); break; case 0xBC9: val = _read_csr(0xBC9); break; case 0xBCA: val = _read_csr(0xBCA); break; case 0xBCC: val = _read_csr(0xBCC); break; case 0xBCB: val = _read_csr(0xBCB); break; case 0x7B0: val = _read_csr(0x7B0); break; case 0x7B1: val = _read_csr(0x7B1); break; case 0x7C8: val = _read_csr(0x7C8); break; case 0x7CC: val = _read_csr(0x7CC); break; case 0x7C9: val = _read_csr(0x7C9); break; case 0x7CA: val = _read_csr(0x7CA); break; case 0x7CB: val = _read_csr(0x7CB); break; case 0x7A0: val = _read_csr(0x7A0); break; case 0x7A1: val = _read_csr(0x7A1); break; case 0x7A2: val = _read_csr(0x7A2); break; case 0xB03: val = _read_csr(0xB03); break; case 0xB04: val = _read_csr(0xB04); break; case 0xB05: val = _read_csr(0xB05); break; case 0xB06: val = _read_csr(0xB06); break; case 0xB83: val = _read_csr(0xB83); break; case 0xB84: val = _read_csr(0xB84); break; case 0xB85: val = _read_csr(0xB85); break; case 0xB86: val = _read_csr(0xB86); break; case 0x323: val = _read_csr(0x323); break; case 0x324: val = _read_csr(0x324); break; case 0x325: val = _read_csr(0x325); break; case 0x326: val = _read_csr(0x326); break; case 0x7F0: val = _read_csr(0x7F0); break; case 0x7F1: val = _read_csr(0x7F1); break; case 0x7F2: val = _read_csr(0x7F2); break; case 0x7C6: val = _read_csr(0x7C6); break; case 0x7F8: val = _read_csr(0x7F8); break; case 0x7C2: val = _read_csr(0x7C2); break; case 0x7F9: val = _read_csr(0x7F9); break; case 0x7D4: val = _read_csr(0x7D4); break; case 0x7D7: val = _read_csr(0x7D7); break; case 0x7D3: val = _read_csr(0x7D3); break; case 0x7D6: val = _read_csr(0x7D6); break; case 0x7D2: val = _read_csr(0x7D2); break; case 0x7D5: val = _read_csr(0x7D5); break; case 0xB07: val = _read_csr(0xB07); break; case 0xB08: val = _read_csr(0xB08); break; case 0xB10: val = _read_csr(0xB10); break; case 0xB87: val = _read_csr(0xB87); break; case 0xB88: val = _read_csr(0xB88); break; case 0xB90: val = _read_csr(0xB90); break; case 0x327: val = _read_csr(0x327); break; case 0x328: val = _read_csr(0x328); break; case 0x330: val = _read_csr(0x330); break; case 0x7CE: val = _read_csr(0x7CE); break; case 0x7CF: val = _read_csr(0x7CF); break; } return val; } void write_csr (uint32_t addr, uint32_t val) { // Since RISC-V does not allow indirect CSR addressing there's a big // 'switch' to handle that. switch (addr) { case 0x304: _write_csr(0x304, val); return; case 0x306: _write_csr(0x306, val); return; case 0x30A: _write_csr(0x30A, val); return; case 0x31A: _write_csr(0x31A, val); return; case 0x340: _write_csr(0x340, val); return; // The test verifies writes to just a handful of CSRs so not all of // them are mentioned here } // Unknown address _write_csr(0xFFF, 0); } volatile unsigned long last_trap = 0xFFFFFFFF; volatile unsigned long fail_count = 0; void test_csr_read_access (uint8_t user_mode) { int ok; // Loop over all implemented CSRs and try reading them. for (size_t i=0; i < sizeof(g_read_csrs) / sizeof(g_read_csrs[0]); ++i) { const struct csr_t* csr = &g_read_csrs[i]; // Attempt CSR read last_trap = 0xFFFFFFFF; volatile unsigned long val = read_csr(csr->addr); // In user mode only unprivileged / user CSRs should be readable. // Accessing others should yield in illegal instruction exception if (user_mode) { if ((csr->addr & 0x300) == 0) { // Unprivileged / user ok = (last_trap == 0xFFFFFFFF); } else { ok = (last_trap == 0x2); // If the access failed check if the read was actually terminated if (ok && val != MAGIC) { printf("0x%08X\n", val); ok = 0; } } } // In machine mode all CSRs should be readable else { ok = (last_trap == 0xFFFFFFFF); } // Count fails fail_count += !ok; printf("%s 0x%03X '%s'\n", ok ? "[ OK ]" : "[ FAIL ]", csr->addr, csr->name); } } void test_csr_write_access (uint8_t user_mode) { int ok = 1; // Loop over all implemented CSRs and try writing them. for (size_t i=0; i < sizeof(g_write_csrs) / sizeof(g_write_csrs[0]); ++i) { const struct csr_t* csr = &g_write_csrs[i]; // Attempt CSR write last_trap = 0xFFFFFFFF; write_csr(csr->addr, 0); // In user mode only unprivileged / user CSRs should be writable. // Accessing others should yield in illegal instruction exception if (user_mode) { if ((csr->addr & 0x300) == 0) { // Unprivileged / user ok = (last_trap == 0xFFFFFFFF); } else { ok = (last_trap == 0x2); } } // In machine mode all CSRs should be readable else { ok = (last_trap == 0xFFFFFFFF); } // Count fails fail_count += !ok; printf("%s 0x%03X '%s'\n", ok ? "[ OK ]" : "[ FAIL ]", csr->addr, csr->name); } } void user_main (); void machine_main (); void trap_handler () { unsigned long mstatus = _read_csr(mstatus); unsigned long mcause = _read_csr(mcause); printf("trap! mstatus=0x%08X, mcause=0x%08X\n", mstatus, mcause); // Store trap cause last_trap = mcause; // If the trap cause is ECALL.U return to machine_main() if (mcause == 0x08) { void* ptr = (void*)machine_main; _write_csr(mepc, (unsigned long)ptr - 4); // -4 as the trap handler advances mepc _write_csr(mstatus, mstatus | (3 << 11)); // MPP=11 (M-mode) } } int main () { printf("\nHello VeeR\n"); // The test requires user mode support if ((_read_csr(misa) & MISA_U) == 0) { printf("ERROR: The test requires user mode support. Aborting.\n"); return -1; } // Test CSR access assuming machine mode printf("Testing CSR read...\n"); test_csr_read_access(0); printf("Testing CSR write...\n"); test_csr_write_access(0); // Write mcounteren.CY and mcounteren.IR to allow access cycle and instret // from user mode _write_csr(0x306, 0x5); // Clear mscratch _write_csr(mscratch, 0); // Go to user mode unsigned long mstatus = _read_csr(mstatus); mstatus &= ~(3 << 11); // MPP = 00 (user) mstatus &= ~(1 << 17); // MPRV = 0 _write_csr(mstatus, mstatus); void* ptr = (void*)user_main; _write_csr(mepc, (unsigned long)ptr); asm volatile ("mret"); return 0; } __attribute__((noreturn)) void user_main () { printf("\nHello from user_main()\n"); // Test CSR access assuming user mode printf("Testing CSR read...\n"); test_csr_read_access(1); printf("Testing CSR write...\n"); test_csr_write_access(1); // Try writing something to mscratch. Ignore exception, later the CSR is // to be read back from machine mode printf("Attempting to write mscratch...\n"); _write_csr(mscratch, MAGIC); // Trigger an ECALL to go to machine mode again asm volatile ("ecall"); while (1); // Make compiler not complain } __attribute__((noreturn)) void machine_main () { printf("\nHello from machine_main()\n"); // Check mscratch. It should not contain the pattern written from user mode printf("Reading mscratch...\n"); unsigned long mscratch = _read_csr(mscratch); if (mscratch == MAGIC) { fail_count++; printf("[ FAIL ] previous write succeeded while it shouldn't\n"); } else { printf("[ OK ]\n"); } printf("\n"); // Terminate the simulation // set the exit code to 0xFF / 0x01 and jump to _finish. unsigned long res = (fail_count == 0) ? 0xFF : 0x01; asm volatile ( "mv a0, %0\n" "j _finish\n" : : "r"(res) ); while (1); // Make compiler not complain } ================================================ FILE: testbench/tests/csr_access/csr_access.ld ================================================ /* SPDX-License-Identifier: Apache-2.0 */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text.init*) *(.text*) } _end = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/tests/csr_access/csr_access.mki ================================================ # SPDX-License-Identifier: Apache-2.0 OFILES = crt0.o csr_access.o veer.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/tests/csr_access/veer.c ================================================ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2023 Antmicro, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include extern volatile char tohost; __attribute__((__noreturn__)) void _exit (int status) { if (!status) tohost = 0xff; else tohost = 0x01; while (1) {}; } int veer_tb_putc(char c, FILE *stream) { (void) stream; tohost = c; return c; } static FILE __stdio = FDEV_SETUP_STREAM(veer_tb_putc, NULL, NULL, _FDEV_SETUP_WRITE); FILE *const stdin = &__stdio; __strong_reference(stdin, stdout); __strong_reference(stdin, stderr); ================================================ FILE: testbench/tests/csr_misa/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .section .text.init .global _start _start: # Setup stack la sp, STACK # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/csr_misa/csr_misa.c ================================================ #include #include #define read_csr(csr) ({ \ unsigned long res; \ asm volatile ("csrr %0, " #csr : "=r"(res)); \ res; \ }) int main () { #ifdef RV_USER_MODE const unsigned int user_mode = 1; #else const unsigned int user_mode = 0; #endif const unsigned int compressed_ext = 1; const unsigned int rv32i_base_isa = 1; const unsigned int int_mult_ext = 1; const unsigned int base = 1; const unsigned long golden = base << 30 | user_mode << 20 | int_mult_ext << 12 | \ rv32i_base_isa << 8 | compressed_ext << 2; // Read and print misa unsigned long misa = read_csr(misa); printf("misa = 0x%08X vs. 0x%08X\n", misa, golden); // Check return (misa == golden) ? 0 : -1; } ================================================ FILE: testbench/tests/csr_misa/csr_misa.ld ================================================ /* SPDX-License-Identifier: Apache-2.0 */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text.init*) *(.text*) } _end = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/tests/csr_misa/csr_misa.mki ================================================ # SPDX-License-Identifier: Apache-2.0 OFILES = crt0.o csr_misa.o printf.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/tests/csr_mseccfg/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .option norvc .option nopic .section .text.init .align 4 .global _start _start: # Setup stack la sp, STACK # Setup trap handler la t0, _trap_entry csrw mtvec, t0 # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr .align 8 _trap_entry: # In this test no trap should happen. Trigger test failure if it does. la a0, 1 j _finish .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/csr_mseccfg/csr_mseccfg.c ================================================ #include #include // Check if VeeR is configured for Smepmp #if !RV_SMEPMP #error "The mseccfg CSR test requires Smepmp to be enabled" #endif // ============================================================================ #define read_csr(csr) ({ \ unsigned long res; \ asm volatile ("csrr %0, %1" : "=r"(res) : "i"(csr)); \ res; \ }) #define write_csr(csr, val) { \ asm volatile ("csrw %0, %1" : : "i"(csr), "r"(val)); \ } // ============================================================================ #define CSR_MSECCFG 0x747 #define CSR_PMPCFG0 0x3A0 #define CSR_PMPADDR0 0x3B0 #define CSR_PMPADDR1 0x3B1 #define CSR_PMPADDR2 0x3B2 #define CSR_PMPADDR3 0x3B3 #define MSECCFG_MML (1 << 0) #define MSECCFG_MMWP (1 << 1) #define MSECCFG_RLB (1 << 2) #define PMPCFG_R (1 << 0) #define PMPCFG_W (1 << 1) #define PMPCFG_X (1 << 2) #define PMPCFG_TOR (1 << 3) #define PMPCFG_L (1 << 7) // ============================================================================ extern uint32_t _code_begin; extern uint32_t _code_end; extern uint32_t _data_begin; extern uint32_t _data_end; // Takes an address of a symbol #define A(x) ((uint32_t)(&(x))) // Converts an address for PMP by shifting it 2 bits to the right #define PMPADDR(x) ((x) >> 2) // Shifts PMP region config bits to appropriate position give the region index #define PMPREGION(cfg,idx) ((cfg) << (8 * ((idx) % 4))) // ============================================================================ int main () { volatile uint32_t reg; // Check that mseccfg is zeroed printf("Checking that mseccfg is all-zero...\n"); reg = read_csr(CSR_MSECCFG); if (reg != 0) { printf("ERROR: mseccfg=0x%08X\n", reg); return -1; } printf("ok.\n"); // Verify that mseccfg.RLB can be set and cleared printf("Checking if mseccfg.RLB is writeable...\n"); reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg | MSECCFG_RLB); reg = read_csr(CSR_MSECCFG); if (!(reg & MSECCFG_RLB)) { printf("ERROR: mseccfg.MML cannot be set\n"); return -1; } reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg & ~MSECCFG_RLB); reg = read_csr(CSR_MSECCFG); if (reg & MSECCFG_RLB) { printf("ERROR: mseccfg.RLB cannot be cleared\n"); return -1; } printf("ok.\n"); // Configure PMP // region 1: _code_begin - _code_end, --X // region 3: _data_begin - _data_end, RW- write_csr(CSR_PMPADDR0, PMPADDR(A(_code_begin))); // PMPADDRx stores address bits 33:2 write_csr(CSR_PMPADDR1, PMPADDR(A(_code_end))); write_csr(CSR_PMPADDR2, PMPADDR(A(_data_begin))); write_csr(CSR_PMPADDR3, PMPADDR(A(_data_end))); uint32_t pmpcfg; pmpcfg = PMPREGION((PMPCFG_TOR | PMPCFG_W | PMPCFG_X), 1) | PMPREGION((PMPCFG_TOR | PMPCFG_W), 2) | PMPREGION((PMPCFG_TOR | PMPCFG_R | PMPCFG_W), 3); write_csr(CSR_PMPCFG0, pmpcfg); // Set mseccfg.RLB and check if the region can be locked and unlocked printf("Checking if mseccfg.RLB=1 allows PMP regions to be unlocked...\n"); reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg | MSECCFG_RLB); // Lock region 1 and check write_csr(CSR_PMPCFG0, pmpcfg | PMPREGION(PMPCFG_L, 1)); reg = read_csr(CSR_PMPCFG0); if (!(reg & PMPREGION(PMPCFG_L, 1))) { printf("ERROR: cannot lock PMP region 0\n"); return -1; } // Unlock region 1 and check write_csr(CSR_PMPCFG0, pmpcfg); reg = read_csr(CSR_PMPCFG0); if (reg & PMPREGION(PMPCFG_L, 1)) { printf("ERROR: cannot unlock PMP region 0\n"); return -1; } printf("ok.\n"); // Verify that when at least one PMP region is locked mseccfg.RLB cannot be // set. printf("Checking if mseccfg.RLB cannot be set if any PMP region is locked...\n"); // Clear RLB reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg & ~MSECCFG_RLB); // Lock region 1 write_csr(CSR_PMPCFG0, pmpcfg | PMPREGION(PMPCFG_L, 1)); // Try setting RLB and check reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg | MSECCFG_RLB); reg = read_csr(CSR_MSECCFG); if (reg & MSECCFG_RLB) { printf("ERROR: mseccfg.RLB can still be set\n"); return -1; } printf("ok.\n"); // Verify that mseccfg.MML cannot be cleared once set printf("Checking if mseccfg.MML cannot be cleared...\n"); // Lock region 3. Region 1 is already locked. This is necessary for the // test as when MML=1 non-locked regions always deny access in M mode write_csr(CSR_PMPCFG0, pmpcfg | PMPREGION(PMPCFG_L, 3)); reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg | MSECCFG_MML); reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg & ~MSECCFG_MML); reg = read_csr(CSR_MSECCFG); if (!(reg & MSECCFG_MML)) { printf("ERROR: mseccfg.MML can be cleared\n"); return -1; } printf("ok.\n"); // Verify that mseccfg.MMWP cannot be cleared once set printf("Checking if mseccfg.MMWP cannot be cleared...\n"); reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg | MSECCFG_MMWP); reg = read_csr(CSR_MSECCFG); write_csr(CSR_MSECCFG, reg & ~MSECCFG_MMWP); reg = read_csr(CSR_MSECCFG); if (!(reg & MSECCFG_MMWP)) { printf("ERROR: mseccfg.MMWP can be cleared\n"); return -1; } printf("ok.\n"); return 0; } ================================================ FILE: testbench/tests/csr_mseccfg/csr_mseccfg.ld ================================================ /* SPDX-License-Identifier: Apache-2.0 */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; _code_begin = .; .text : { *(.text.init*) *(.text*) } _code_end = .; _data_begin = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } _data_end = .; } ================================================ FILE: testbench/tests/csr_mseccfg/csr_mseccfg.mki ================================================ # SPDX-License-Identifier: Apache-2.0 OFILES = crt0.o csr_mseccfg.o printf.o TEST_CFLAGS = -g -O0 -falign-functions=16 ================================================ FILE: testbench/tests/csr_mstatus/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .section .text.init .global _start _start: # Setup stack la sp, STACK # Setup PMP # Region 0 TOR 0x00000000-0xFFFFFFFF RWX li t0, 0xFFFFFFFF csrw pmpaddr0, t0 li t0, 0x0000000F csrw pmpcfg0, t0 # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/csr_mstatus/csr_mstatus.c ================================================ #include #define read_csr(csr) ({ \ unsigned long res; \ asm volatile ("csrr %0, " #csr : "=r"(res)); \ res; \ }) #define write_csr(csr, val) { \ asm volatile ("csrw " #csr ", %0" : : "r"(val)); \ } #define MISA_U (1 << 20) int main () { // The test requires user mode support if ((read_csr(misa) & MISA_U) == 0) { printf("ERROR: The test requires user mode support. Aborting.\n"); return -1; } unsigned long prv, cur; int res = 0; // Test privilete mode availablilty by writing to mstatus.MPP and reading // it back. The value should match. // M-mode printf("M mode:\n"); prv = read_csr(mstatus); prv &= ~(3 << 11); prv |= (3 << 11); // MPP = 11 printf(" 0x%08X\n", prv); write_csr(mstatus, prv); cur = read_csr(mstatus); printf(" 0x%08X\n", cur); if (((prv ^ cur) & (3 << 11)) == 0) { printf(" ok.\n"); } else { printf(" not supported.\n"); res = -1; // error } // S-mode printf("S mode:\n"); prv = read_csr(mstatus); prv &= ~(3 << 11); prv |= (1 << 11); // MPP = 01 printf(" 0x%08X\n", prv); write_csr(mstatus, prv); cur = read_csr(mstatus); printf(" 0x%08X\n", cur); if (((prv ^ cur) & (3 << 11)) == 0) { printf(" ok.\n"); res = -1; // error } else { printf(" not supported.\n"); } // U-mode printf("U mode:\n"); prv = read_csr(mstatus); prv &= ~(3 << 11); // MPP = 00 printf(" 0x%08X\n", prv); write_csr(mstatus, prv); cur = read_csr(mstatus); printf(" 0x%08X\n", cur); if (((prv ^ cur) & (3 << 11)) == 0) { printf(" ok.\n"); } else { printf(" not supported.\n"); res = -1; // error } // Test the MPRV bit printf("MPRV\n"); prv = read_csr(mstatus); prv |= (1 << 17); // MPRV=1 printf(" 0x%08X\n", prv); write_csr(mstatus, prv); cur = read_csr(mstatus); printf(" 0x%08X\n", cur); if (((prv ^ cur) & (3 << 17)) != 0) { printf(" cannot set!\n"); res = -1; } else { printf(" ok.\n"); } prv = read_csr(mstatus); prv &= ~(1 << 17); // MPRV=0 printf(" 0x%08X\n", prv); write_csr(mstatus, prv); cur = read_csr(mstatus); printf(" 0x%08X\n", cur); if (((prv ^ cur) & (3 << 17)) != 0) { printf(" cannot clear!\n"); res = -1; } else { printf(" ok.\n"); } return res; } ================================================ FILE: testbench/tests/csr_mstatus/csr_mstatus.ld ================================================ /* SPDX-License-Identifier: Apache-2.0 */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text.init*) *(.text*) } _end = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/tests/csr_mstatus/csr_mstatus.mki ================================================ # SPDX-License-Identifier: Apache-2.0 OFILES = crt0.o csr_mstatus.o printf.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/tests/dhry/dhry.h ================================================ #pragma once /* **************************************************************************** * * "DHRYSTONE" Benchmark Program * ----------------------------- * * Version: C, Version 2.1 * * File: dhry.h (part 1 of 3) * * Date: May 25, 1988 * * Author: Reinhold P. Weicker * Siemens AG, E STE 35 * Postfach 3240 * 8520 Erlangen * Germany (West) * Phone: [xxx-49]-9131-7-20330 * (8-17 Central European Time) * Usenet: ..!mcvax!unido!estevax!weicker * * Original Version (in Ada) published in * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984), * pp. 1013 - 1030, together with the statistics * on which the distribution of statements etc. is based. * * In this C version, the following C library functions are used: * - strcpy, strcmp (inside the measurement loop) * - printf, scanf (outside the measurement loop) * In addition, Berkeley UNIX system calls "times ()" or "time ()" * are used for execution time measurement. For measurements * on other systems, these calls have to be changed. * * Collection of Results: * Reinhold Weicker (address see above) and * * Rick Richardson * PC Research. Inc. * 94 Apple Orchard Drive * Tinton Falls, NJ 07724 * Phone: (201) 389-8963 (9-17 EST) * Usenet: ...!uunet!pcrat!rick * * Please send results to Rick Richardson and/or Reinhold Weicker. * Complete information should be given on hardware and software used. * Hardware information includes: Machine type, CPU, type and size * of caches; for microprocessors: clock frequency, memory speed * (number of wait states). * Software information includes: Compiler (and runtime library) * manufacturer and version, compilation switches, OS version. * The Operating System version may give an indication about the * compiler; Dhrystone itself performs no OS calls in the measurement loop. * * The complete output generated by the program should be mailed * such that at least some checks for correctness can be made. * *************************************************************************** * * History: This version C/2.1 has been made for two reasons: * * 1) There is an obvious need for a common C version of * Dhrystone, since C is at present the most popular system * programming language for the class of processors * (microcomputers, minicomputers) where Dhrystone is used most. * There should be, as far as possible, only one C version of * Dhrystone such that results can be compared without * restrictions. In the past, the C versions distributed * by Rick Richardson (Version 1.1) and by Reinhold Weicker * had small (though not significant) differences. * * 2) As far as it is possible without changes to the Dhrystone * statistics, optimizing compilers should be prevented from * removing significant statements. * * This C version has been developed in cooperation with * Rick Richardson (Tinton Falls, NJ), it incorporates many * ideas from the "Version 1.1" distributed previously by * him over the UNIX network Usenet. * I also thank Chaim Benedelac (National Semiconductor), * David Ditzel (SUN), Earl Killian and John Mashey (MIPS), * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley) * for their help with comments on earlier versions of the * benchmark. * * Changes: In the initialization part, this version follows mostly * Rick Richardson's version distributed via Usenet, not the * version distributed earlier via floppy disk by Reinhold Weicker. * As a concession to older compilers, names have been made * unique within the first 8 characters. * Inside the measurement loop, this version follows the * version previously distributed by Reinhold Weicker. * * At several places in the benchmark, code has been added, * but within the measurement loop only in branches that * are not executed. The intention is that optimizing compilers * should be prevented from moving code out of the measurement * loop, or from removing code altogether. Since the statements * that are executed within the measurement loop have NOT been * changed, the numbers defining the "Dhrystone distribution" * (distribution of statements, operand types and locality) * still hold. Except for sophisticated optimizing compilers, * execution times for this version should be the same as * for previous versions. * * Since it has proven difficult to subtract the time for the * measurement loop overhead in a correct way, the loop check * has been made a part of the benchmark. This does have * an impact - though a very minor one - on the distribution * statistics which have been updated for this version. * * All changes within the measurement loop are described * and discussed in the companion paper "Rationale for * Dhrystone version 2". * * Because of the self-imposed limitation that the order and * distribution of the executed statements should not be * changed, there are still cases where optimizing compilers * may not generate code for some statements. To a certain * degree, this is unavoidable for small synthetic benchmarks. * Users of the benchmark are advised to check code listings * whether code is generated for all statements of Dhrystone. * * Version 2.1 is identical to version 2.0 distributed via * the UNIX network Usenet in March 1988 except that it corrects * some minor deficiencies that were found by users of version 2.0. * The only change within the measurement loop is that a * non-executed "else" part was added to the "if" statement in * Func_3, and a non-executed "else" part removed from Proc_3. * *************************************************************************** * * Defines: The following "Defines" are possible: * -DREG=register (default: Not defined) * As an approximation to what an average C programmer * might do, the "register" storage class is applied * (if enabled by -DREG=register) * - for local variables, if they are used (dynamically) * five or more times * - for parameters if they are used (dynamically) * six or more times * Note that an optimal "register" strategy is * compiler-dependent, and that "register" declarations * do not necessarily lead to faster execution. * -DNOSTRUCTASSIGN (default: Not defined) * Define if the C compiler does not support * assignment of structures. * -DNOENUMS (default: Not defined) * Define if the C compiler does not support * enumeration types. * -DTIMES (default) * -DTIME * The "times" function of UNIX (returning process times) * or the "time" function (returning wallclock time) * is used for measurement. * For single user machines, "time ()" is adequate. For * multi-user machines where you cannot get single-user * access, use the "times ()" function. If you have * neither, use a stopwatch in the dead of night. * "printf"s are provided marking the points "Start Timer" * and "Stop Timer". DO NOT use the UNIX "time(1)" * command, as this will measure the total time to * run this program, which will (erroneously) include * the time to allocate storage (malloc) and to perform * the initialization. * -DHZ=nnn * In Berkeley UNIX, the function "times" returns process * time in 1/HZ seconds, with HZ = 60 for most systems. * CHECK YOUR SYSTEM DESCRIPTION BEFORE YOU JUST APPLY * A VALUE. * *************************************************************************** * * Compilation model and measurement (IMPORTANT): * * This C version of Dhrystone consists of three files: * - dhry.h (this file, containing global definitions and comments) * - dhry_1.c (containing the code corresponding to Ada package Pack_1) * - dhry_2.c (containing the code corresponding to Ada package Pack_2) * * The following "ground rules" apply for measurements: * - Separate compilation * - No procedure merging * - Otherwise, compiler optimizations are allowed but should be indicated * - Default results are those without register declarations * See the companion paper "Rationale for Dhrystone Version 2" for a more * detailed discussion of these ground rules. * * For 16-Bit processors (e.g. 80186, 80286), times for all compilation * models ("small", "medium", "large" etc.) should be given if possible, * together with a definition of these models for the compiler system used. * ************************************************************************** * * Dhrystone (C version) statistics: * * [Comment from the first distribution, updated for version 2. * Note that because of language differences, the numbers are slightly * different from the Ada version.] * * The following program contains statements of a high level programming * language (here: C) in a distribution considered representative: * * assignments 52 (51.0 %) * control statements 33 (32.4 %) * procedure, function calls 17 (16.7 %) * * 103 statements are dynamically executed. The program is balanced with * respect to the three aspects: * * - statement type * - operand type * - operand locality * operand global, local, parameter, or constant. * * The combination of these three aspects is balanced only approximately. * * 1. Statement Type: * ----------------- number * * V1 = V2 9 * (incl. V1 = F(..) * V = Constant 12 * Assignment, 7 * with array element * Assignment, 6 * with record component * -- * 34 34 * * X = Y +|-|"&&"|"|" Z 5 * X = Y +|-|"==" Constant 6 * X = X +|- 1 3 * X = Y *|/ Z 2 * X = Expression, 1 * two operators * X = Expression, 1 * three operators * -- * 18 18 * * if .... 14 * with "else" 7 * without "else" 7 * executed 3 * not executed 4 * for ... 7 | counted every time * while ... 4 | the loop condition * do ... while 1 | is evaluated * switch ... 1 * break 1 * declaration with 1 * initialization * -- * 34 34 * * P (...) procedure call 11 * user procedure 10 * library procedure 1 * X = F (...) * function call 6 * user function 5 * library function 1 * -- * 17 17 * --- * 103 * * The average number of parameters in procedure or function calls * is 1.82 (not counting the function values aX * * * 2. Operators * ------------ * number approximate * percentage * * Arithmetic 32 50.8 * * + 21 33.3 * - 7 11.1 * * 3 4.8 * / (int div) 1 1.6 * * Comparison 27 42.8 * * == 9 14.3 * /= 4 6.3 * > 1 1.6 * < 3 4.8 * >= 1 1.6 * <= 9 14.3 * * Logic 4 6.3 * * && (AND-THEN) 1 1.6 * | (OR) 1 1.6 * ! (NOT) 2 3.2 * * -- ----- * 63 100.1 * * * 3. Operand Type (counted once per operand reference): * --------------- * number approximate * percentage * * Integer 175 72.3 % * Character 45 18.6 % * Pointer 12 5.0 % * String30 6 2.5 % * Array 2 0.8 % * Record 2 0.8 % * --- ------- * 242 100.0 % * * When there is an access path leading to the final operand (e.g. a record * component), only the final data type on the access path is counted. * * * 4. Operand Locality: * ------------------- * number approximate * percentage * * local variable 114 47.1 % * global variable 22 9.1 % * parameter 45 18.6 % * value 23 9.5 % * reference 22 9.1 % * function result 6 2.5 % * constant 55 22.7 % * --- ------- * 242 100.0 % * * * The program does not compute anything meaningful, but it is syntactically * and semantically correct. All variables have a value assigned to them * before they are used as a source operand. * * There has been no explicit effort to account for the effects of a * cache, or to balance the use of long or short displacements for code or * data. * *************************************************************************** */ /* Compiler and system dependent definitions: */ #ifndef TIME #undef TIMES #define TIMES #endif /* Use times(2) time function unless */ /* explicitly defined otherwise */ #ifdef MSC_CLOCK #undef HZ #undef TIMES #include #define HZ CLK_TCK #endif /* Use Microsoft C hi-res clock */ #ifdef TIMES #include #include #ifndef HZ #define HZ 100 #endif /* for "times" */ #endif #define Mic_secs_Per_Second 1000000.0 /* Berkeley UNIX C returns process times in seconds/HZ */ #ifdef NOSTRUCTASSIGN #define structassign(d, s) memcpy(&(d), &(s), sizeof(d)) #else #define structassign(d, s) d = s #endif #ifdef NOENUM #define Ident_1 0 #define Ident_2 1 #define Ident_3 2 #define Ident_4 3 #define Ident_5 4 typedef int Enumeration; #else typedef enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5} Enumeration; #endif /* for boolean and enumeration types in Ada, Pascal */ /* General definitions: */ //#include /* for strcpy, strcmp */ #define Null 0 /* Value of a Null pointer */ #define true 1 #define false 0 typedef int One_Thirty; typedef int One_Fifty; typedef char Capital_Letter; typedef int Boolean; typedef char Str_30 [31]; typedef int Arr_1_Dim [50]; typedef int Arr_2_Dim [50] [50]; typedef struct record { struct record *Ptr_Comp; Enumeration Discr; union { struct { Enumeration Enum_Comp; int Int_Comp; char Str_Comp [31]; } var_1; struct { Enumeration E_Comp_2; char Str_2_Comp [31]; } var_2; struct { char Ch_1_Comp; char Ch_2_Comp; } var_3; } variant; } Rec_Type, *Rec_Pointer; ================================================ FILE: testbench/tests/dhry/dhry.mki ================================================ OFILES = crt0.o dhry_1.o dhry_2.o printf.o TEST_CFLAGS = -g -O3 ================================================ FILE: testbench/tests/dhry/dhry_1.c ================================================ #define VEER /* **************************************************************************** * * "DHRYSTONE" Benchmark Program * ----------------------------- * * Version: C, Version 2.1 * * File: dhry_1.c (part 2 of 3) * * Date: May 25, 1988 * * Author: Reinhold P. Weicker * **************************************************************************** */ #ifdef VEER #include #include extern uint64_t get_mcycle(); #endif #include "dhry.h" /* Global Variables: */ Rec_Pointer Ptr_Glob, Next_Ptr_Glob; int Int_Glob; Boolean Bool_Glob; char Ch_1_Glob, Ch_2_Glob; int Arr_1_Glob [50]; int Arr_2_Glob [50] [50]; Enumeration Func_1 (); /* forward declaration necessary since Enumeration may not simply be int */ #ifndef REG Boolean Reg = false; #define REG /* REG becomes defined as empty */ /* i.e. no register variables */ #else Boolean Reg = true; #endif /* variables for time measurement: */ #ifdef TIMES struct tms time_info; #define Too_Small_Time (2*HZ) /* Measurements should last at least about 2 seconds */ #endif #ifdef TIME extern long time(); /* see library function "time" */ #define Too_Small_Time 2 /* Measurements should last at least 2 seconds */ #endif #ifdef MSC_CLOCK extern clock_t clock(); #define Too_Small_Time (2*HZ) #endif long Begin_Time, End_Time, User_Time; float Microseconds, Dhrystones_Per_Second; /* end of variables for time measurement */ extern char* strcpy(char*, const char*); extern Boolean Func_2 (Str_30, Str_30); extern void Proc_7 (One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, One_Fifty *Int_Par_Ref); extern void Proc_8 (Arr_1_Dim Arr_1_Par_Ref, Arr_2_Dim Arr_2_Par_Ref, int Int_1_Par_Val, int Int_2_Par_Val); extern void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par); void Proc_5(); void Proc_4(); void Proc_1(Rec_Pointer Ptr_Val_Par); void Proc_2(One_Fifty *Int_Par_Ref); void Proc_3(Rec_Pointer *Ptr_Ref_Par); int main () /*****/ /* main program, corresponds to procedures */ /* Main and Proc_0 in the Ada version */ { One_Fifty Int_1_Loc; REG One_Fifty Int_2_Loc; One_Fifty Int_3_Loc; REG char Ch_Index; Enumeration Enum_Loc; Str_30 Str_1_Loc; Str_30 Str_2_Loc; REG int Run_Index; REG int Number_Of_Runs; /* Initializations */ Rec_Type rec0; Rec_Type rec1; Next_Ptr_Glob = &rec0; Ptr_Glob = &rec1; Ptr_Glob->Ptr_Comp = Next_Ptr_Glob; Ptr_Glob->Discr = Ident_1; Ptr_Glob->variant.var_1.Enum_Comp = Ident_3; Ptr_Glob->variant.var_1.Int_Comp = 40; strcpy (Ptr_Glob->variant.var_1.Str_Comp, "DHRYSTONE PROGRAM, SOME STRING"); strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING"); Arr_2_Glob [8][7] = 10; /* Was missing in published program. Without this statement, */ /* Arr_2_Glob [8][7] would have an undefined value. */ /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */ /* overflow may occur for this array element. */ printf ("Dhrystone Benchmark, Version 2.1 (Language: C)\n"); if (Reg) { printf ("Program compiled with 'register' attribute\n"); } else { printf ("Program compiled without 'register' attribute\n"); } #ifndef VEER printf ("Please give the number of runs through the benchmark: "); { int n = 1000; scanf ("%d", &n); Number_Of_Runs = n; } printf ("\n"); #else // We do not have scanf. Hardwire number of runs. Number_Of_Runs = 1000; #endif printf ("Execution starts, %d runs through Dhrystone\n", Number_Of_Runs); /***************/ /* Start timer */ /***************/ #ifdef VEER Begin_Time = get_mcycle(); #else #ifdef TIMES times (&time_info); Begin_Time = (long) time_info.tms_utime; #endif #ifdef TIME Begin_Time = time ( (long *) 0); #endif #ifdef MSC_CLOCK Begin_Time = clock(); #endif #endif __asm("__perf_start:"); for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index) { __asm("__loop_start:"); Proc_5(); Proc_4(); /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */ Int_1_Loc = 2; Int_2_Loc = 3; strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING"); Enum_Loc = Ident_2; Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc); /* Bool_Glob == 1 */ while (Int_1_Loc < Int_2_Loc) /* loop body executed once */ { Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc; /* Int_3_Loc == 7 */ Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc); /* Int_3_Loc == 7 */ Int_1_Loc += 1; } /* while */ /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc); /* Int_Glob == 5 */ Proc_1 (Ptr_Glob); for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index) /* loop body executed twice */ { if (Enum_Loc == Func_1 (Ch_Index, 'C')) /* then, not executed */ { Proc_6 (Ident_1, &Enum_Loc); strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING"); Int_2_Loc = Run_Index; Int_Glob = Run_Index; } } /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */ Int_2_Loc = Int_2_Loc * Int_1_Loc; Int_1_Loc = Int_2_Loc / Int_3_Loc; Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc; /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */ Proc_2 (&Int_1_Loc); /* Int_1_Loc == 5 */ } /* loop "for Run_Index" */ __asm("__perf_end:"); /**************/ /* Stop timer */ /**************/ #ifdef VEER End_Time = get_mcycle(); printf("End_time=%d\n", (int) End_Time); #else #ifdef TIMES times (&time_info); End_Time = (long) time_info.tms_utime; #endif #ifdef TIME End_Time = time ( (long *) 0); #endif #ifdef MSC_CLOCK End_Time = clock(); #endif #endif printf ("Final values of the variables used in the benchmark:\n\n"); printf ("Int_Glob: %d\n", Int_Glob); printf (" should be: %d\n", 5); printf ("Bool_Glob: %d\n", Bool_Glob); printf (" should be: %d\n", 1); printf ("Ch_1_Glob: %c\n", Ch_1_Glob); printf (" should be: %c\n", 'A'); printf ("Ch_2_Glob: %c\n", Ch_2_Glob); printf (" should be: %c\n", 'B'); printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]); printf (" should be: %d\n", 7); printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]); printf (" should be: Number_Of_Runs + 10\n"); printf ("Ptr_Glob->Ptr_Comp: %x\n", (int) Ptr_Glob->Ptr_Comp); printf (" should be: (implementation-dependent)\n"); printf (" Discr: %d\n", Ptr_Glob->Discr); printf (" should be: %d\n", 0); printf (" Enum_Comp: %d\n", Ptr_Glob->variant.var_1.Enum_Comp); printf (" should be: %d\n", 2); printf (" Int_Comp: %d\n", Ptr_Glob->variant.var_1.Int_Comp); printf (" should be: %d\n", 17); printf (" Str_Comp: %s", Ptr_Glob->variant.var_1.Str_Comp); printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); printf ("Next_Ptr_Glob->Ptr_Comp:%x\n", (int) Next_Ptr_Glob->Ptr_Comp); printf (" should be: (implementation-dependent), same as above\n"); printf (" Discr: %d\n", Next_Ptr_Glob->Discr); printf (" should be: %d\n", 0); printf (" Enum_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Enum_Comp); printf (" should be: %d\n", 1); printf (" Int_Comp: %d\n", Next_Ptr_Glob->variant.var_1.Int_Comp); printf (" should be: %d\n", 18); printf (" Str_Comp: %s", Next_Ptr_Glob->variant.var_1.Str_Comp); printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n"); printf ("Int_1_Loc: %d\n", Int_1_Loc); printf (" should be: %d\n", 5); printf ("Int_2_Loc: %d\n", Int_2_Loc); printf (" should be: %d\n", 13); printf ("Int_3_Loc: %d\n", Int_3_Loc); printf (" should be: %d\n", 7); printf ("Enum_Loc: %d\n", Enum_Loc); printf (" should be: %d\n", 1); printf ("Str_1_Loc: %s", Str_1_Loc); printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n"); printf ("Str_2_Loc: %s", Str_2_Loc); printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n"); printf ("\n"); User_Time = End_Time - Begin_Time; if (User_Time < Too_Small_Time) { printf ("User time %d\n", User_Time); printf ("Measured time too small to obtain meaningful results\n"); printf ("Please increase number of runs\n"); printf ("\n"); } else { #ifdef VEER printf ("Run time = %d clocks for %d Dhrystones\n", User_Time, Number_Of_Runs ); printf ("Dhrystones per Second per MHz: "); printf ("%d.%02d", 1000000*Number_Of_Runs/User_Time,(100000000*Number_Of_Runs/User_Time) % 100); #else #ifdef TIME Microseconds = (float) User_Time * Mic_secs_Per_Second / (float) Number_Of_Runs; Dhrystones_Per_Second = (float) Number_Of_Runs / (float) User_Time; #else Microseconds = (float) User_Time * Mic_secs_Per_Second / ((float) HZ * ((float) Number_Of_Runs)); Dhrystones_Per_Second = ((float) HZ * (float) Number_Of_Runs) / (float) User_Time; #endif printf ("Microseconds for one run through Dhrystone: "); printf ("%6.1f \n", Microseconds); printf ("Dhrystones per Second: "); printf ("%6.1f \n", Dhrystones_Per_Second); #endif printf ("\n"); } return 0; } void Proc_1 (Ptr_Val_Par) /******************/ REG Rec_Pointer Ptr_Val_Par; /* executed once */ { REG Rec_Pointer Next_Record = Ptr_Val_Par->Ptr_Comp; /* == Ptr_Glob_Next */ /* Local variable, initialized with Ptr_Val_Par->Ptr_Comp, */ /* corresponds to "rename" in Ada, "with" in Pascal */ structassign (*Ptr_Val_Par->Ptr_Comp, *Ptr_Glob); Ptr_Val_Par->variant.var_1.Int_Comp = 5; Next_Record->variant.var_1.Int_Comp = Ptr_Val_Par->variant.var_1.Int_Comp; Next_Record->Ptr_Comp = Ptr_Val_Par->Ptr_Comp; Proc_3 (&Next_Record->Ptr_Comp); /* Ptr_Val_Par->Ptr_Comp->Ptr_Comp == Ptr_Glob->Ptr_Comp */ if (Next_Record->Discr == Ident_1) /* then, executed */ { Next_Record->variant.var_1.Int_Comp = 6; Proc_6 (Ptr_Val_Par->variant.var_1.Enum_Comp, &Next_Record->variant.var_1.Enum_Comp); Next_Record->Ptr_Comp = Ptr_Glob->Ptr_Comp; Proc_7 (Next_Record->variant.var_1.Int_Comp, 10, &Next_Record->variant.var_1.Int_Comp); } else /* not executed */ structassign (*Ptr_Val_Par, *Ptr_Val_Par->Ptr_Comp); } /* Proc_1 */ void Proc_2 (Int_Par_Ref) /******************/ /* executed once */ /* *Int_Par_Ref == 1, becomes 4 */ One_Fifty *Int_Par_Ref; { One_Fifty Int_Loc; Enumeration Enum_Loc; Int_Loc = *Int_Par_Ref + 10; do /* executed once */ if (Ch_1_Glob == 'A') /* then, executed */ { Int_Loc -= 1; *Int_Par_Ref = Int_Loc - Int_Glob; Enum_Loc = Ident_1; } /* if */ while (Enum_Loc != Ident_1); /* true */ } /* Proc_2 */ void Proc_3 (Ptr_Ref_Par) /******************/ /* executed once */ /* Ptr_Ref_Par becomes Ptr_Glob */ Rec_Pointer *Ptr_Ref_Par; { if (Ptr_Glob != Null) /* then, executed */ *Ptr_Ref_Par = Ptr_Glob->Ptr_Comp; Proc_7 (10, Int_Glob, &Ptr_Glob->variant.var_1.Int_Comp); } /* Proc_3 */ void Proc_4 () /* without parameters */ /*******/ /* executed once */ { Boolean Bool_Loc; Bool_Loc = Ch_1_Glob == 'A'; Bool_Glob = Bool_Loc | Bool_Glob; Ch_2_Glob = 'B'; } /* Proc_4 */ void Proc_5 () /* without parameters */ /*******/ /* executed once */ { Ch_1_Glob = 'A'; Bool_Glob = false; } /* Proc_5 */ /* Procedure for the assignment of structures, */ /* if the C compiler doesn't support this feature */ #ifdef NOSTRUCTASSIGN memcpy (d, s, l) register char *d; register char *s; register int l; { while (l--) *d++ = *s++; } #endif ================================================ FILE: testbench/tests/dhry/dhry_2.c ================================================ /* **************************************************************************** * * "DHRYSTONE" Benchmark Program * ----------------------------- * * Version: C, Version 2.1 * * File: dhry_2.c (part 3 of 3) * * Date: May 25, 1988 * * Author: Reinhold P. Weicker * **************************************************************************** */ #include "dhry.h" #ifndef REG #define REG /* REG becomes defined as empty */ /* i.e. no register variables */ #endif extern int Int_Glob; extern char Ch_1_Glob; #if 0 int strcmp(const char* s1, const char* s2) { while (*s1 && *s1 == *s2) { s1++; s2++; } if (*s1 == *s2) return 0; return *s1 > *s2? 1 : -1; } #else extern int strcmp( char* s1, char* s2); #endif Boolean Func_3 (Enumeration Enum_Par_Val); void Proc_6 (Enum_Val_Par, Enum_Ref_Par) /*********************************/ /* executed once */ /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */ Enumeration Enum_Val_Par; Enumeration *Enum_Ref_Par; { *Enum_Ref_Par = Enum_Val_Par; if (! Func_3 (Enum_Val_Par)) /* then, not executed */ *Enum_Ref_Par = Ident_4; switch (Enum_Val_Par) { case Ident_1: *Enum_Ref_Par = Ident_1; break; case Ident_2: if (Int_Glob > 100) /* then */ *Enum_Ref_Par = Ident_1; else *Enum_Ref_Par = Ident_4; break; case Ident_3: /* executed */ *Enum_Ref_Par = Ident_2; break; case Ident_4: break; case Ident_5: *Enum_Ref_Par = Ident_3; break; } /* switch */ } /* Proc_6 */ void Proc_7 (Int_1_Par_Val, Int_2_Par_Val, Int_Par_Ref) /**********************************************/ /* executed three times */ /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */ /* Int_Par_Ref becomes 7 */ /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */ /* Int_Par_Ref becomes 17 */ /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */ /* Int_Par_Ref becomes 18 */ One_Fifty Int_1_Par_Val; One_Fifty Int_2_Par_Val; One_Fifty *Int_Par_Ref; { One_Fifty Int_Loc; Int_Loc = Int_1_Par_Val + 2; *Int_Par_Ref = Int_2_Par_Val + Int_Loc; } /* Proc_7 */ void Proc_8 (Arr_1_Par_Ref, Arr_2_Par_Ref, Int_1_Par_Val, Int_2_Par_Val) /*********************************************************************/ /* executed once */ /* Int_Par_Val_1 == 3 */ /* Int_Par_Val_2 == 7 */ Arr_1_Dim Arr_1_Par_Ref; Arr_2_Dim Arr_2_Par_Ref; int Int_1_Par_Val; int Int_2_Par_Val; { REG One_Fifty Int_Index; REG One_Fifty Int_Loc; Int_Loc = Int_1_Par_Val + 5; Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val; Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc]; Arr_1_Par_Ref [Int_Loc+30] = Int_Loc; for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index) Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc; Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1; Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc]; Int_Glob = 5; } /* Proc_8 */ Enumeration Func_1 (Ch_1_Par_Val, Ch_2_Par_Val) /*************************************************/ /* executed three times */ /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */ /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */ /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */ Capital_Letter Ch_1_Par_Val; Capital_Letter Ch_2_Par_Val; { Capital_Letter Ch_1_Loc; Capital_Letter Ch_2_Loc; Ch_1_Loc = Ch_1_Par_Val; Ch_2_Loc = Ch_1_Loc; if (Ch_2_Loc != Ch_2_Par_Val) /* then, executed */ return (Ident_1); else /* not executed */ { Ch_1_Glob = Ch_1_Loc; return (Ident_2); } } /* Func_1 */ Boolean Func_2 (Str_1_Par_Ref, Str_2_Par_Ref) /*************************************************/ /* executed once */ /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */ /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */ Str_30 Str_1_Par_Ref; Str_30 Str_2_Par_Ref; { REG One_Thirty Int_Loc; Capital_Letter Ch_Loc; Int_Loc = 2; while (Int_Loc <= 2) /* loop body executed once */ if (Func_1 (Str_1_Par_Ref[Int_Loc], Str_2_Par_Ref[Int_Loc+1]) == Ident_1) /* then, executed */ { Ch_Loc = 'A'; Int_Loc += 1; } /* if, while */ if (Ch_Loc >= 'W' && Ch_Loc < 'Z') /* then, not executed */ Int_Loc = 7; if (Ch_Loc == 'R') /* then, not executed */ return (true); else /* executed */ { if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0) /* then, not executed */ { Int_Loc += 7; Int_Glob = Int_Loc; return (true); } else /* executed */ return (false); } /* if Ch_Loc */ } /* Func_2 */ Boolean Func_3 (Enum_Par_Val) /***************************/ /* executed once */ /* Enum_Par_Val == Ident_3 */ Enumeration Enum_Par_Val; { Enumeration Enum_Loc; Enum_Loc = Enum_Par_Val; if (Enum_Loc == Ident_3) /* then, executed */ return (true); else /* not executed */ return (false); } /* Func_3 */ ================================================ FILE: testbench/tests/ecc/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 #include "defines.h" .section .text.init .global _start _start: // enable caching, except region 0xd li t0, 0x59555555 csrw 0x7c0, t0 la sp, STACK la t0, _trap_handler csrw mtvec, t0 call main .global _finish _finish: la t0, tohost li t1, 0xff sb t1, 0(t0) // DemoTB test termination li t1, 1 sw t1, 0(t0) // Whisper test termination beq x0, x0, _finish .rept 10 nop .endr .global _trap_handler _trap_handler: call trap_handler j _start .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/ecc/ecc.c ================================================ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2024 Antmicro * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #define STDOUT 0xd0580000 volatile char* stdout = (char *)STDOUT; #define MFDC_DISABLE_ECC_MASK 0x100 #define INJECT_ICCM_SINGLE_BIT 0xe0 #define INJECT_ICCM_DOUBLE_BIT 0xe1 #define INJECT_DCCM_SINGLE_BIT 0xe2 #define INJECT_DCCM_DOUBLE_BIT 0xe3 #define DISABLE_ERROR_INJECTION 0xe4 #define TEST_PASSED 0xff #define TEST_FAILED 0x01 #define ICCM_SADDR 0xee000000 #define DCCM_SADDR 0xf0040000 void execute_from_iccm (void) __attribute__ ((aligned(4),section(".iccm_data0"))); volatile uint32_t boot_count __attribute__((section(".dccm.persistent"))) = 0; uint32_t dccm_test, iccm_test; extern const int ICCM_ADDR, DCCM_ADDR; extern uintptr_t iccm_start, iccm_end; extern int printf(const char* format, ...); extern int putchar(int c); void sleep(uint32_t count) { for (uint32_t slp = 0; slp < count; slp++) { __asm__ volatile ("nop"); // Sleep loop as "nop" } } int read_mcause(void) { uint32_t mcause; __asm__ volatile ("csrr %0, %1" : "=r" (mcause) /* output: variable */ : "i" (0x342) /* input : immediate */ : /* clobbers: none */); return mcause; } int read_mscause(void) { uint32_t mscause; __asm__ volatile ("csrr %0, %1" : "=r" (mscause) /* output: variable */ : "i" (0x7FF) /* input : immediate */ : /* clobbers: none */); return mscause; } int read_mfdc(void) { uint32_t mfdc; __asm__ volatile ("csrr %0, %1" : "=r" (mfdc) /* output: variable */ : "i" (0x7F9) /* input : immediate */ : /* clobbers: none */); return mfdc; } int read_mdccmect(void) { uint32_t mdccmect; __asm__ volatile ("csrr %0, %1" : "=r" (mdccmect) /* output: variable */ : "i" (0x7F2) /* input : immediate */ : /* clobbers: none */); return mdccmect; } int read_miccmect(void) { uint32_t miccmect; __asm__ volatile ("csrr %0, %1" : "=r" (miccmect) /* output: variable */ : "i" (0x7F1) /* input : immediate */ : /* clobbers: none */); return miccmect; } void clear_causes(void) { __asm__ volatile ("csrw %0, %1" : /* output: none */ : "i" (0x342), "i" (0) /* input : immediate */ : /* clobbers: none */); __asm__ volatile ("csrw %0, %1" : /* output: none */ : "i" (0x7FF), "i" (0) /* input : immediate */ : /* clobbers: none */); } void disable_ecc_check(void) { uint32_t mfdc_disable_ecc_mask = MFDC_DISABLE_ECC_MASK; __asm__ volatile ("csrs %0, %1" : /* output: none */ : "i" (0x7F9), "r" (mfdc_disable_ecc_mask) /* input : immediate */ : /* clobbers: none */); } void enable_ecc_check(void) { uint32_t mfdc_disable_ecc_mask = MFDC_DISABLE_ECC_MASK; __asm__ volatile ("csrc %0, %1" : /* output: none */ : "i" (0x7F9), "r" (mfdc_disable_ecc_mask) /* input : immediate */ : /* clobbers: none */); } void trap_handler(void) { uint32_t mcause, mscause, mfdc; mfdc = read_mfdc(); if (mfdc & MFDC_DISABLE_ECC_MASK) { printf("Trap hit while ECC check is disabled!\n"); putchar(TEST_FAILED); } mcause = read_mcause(); mscause = read_mscause(); clear_causes(); if (((mcause == 0x5 && mscause == 0x1) || (mcause == 0x7 && mscause == 0x1)) && dccm_test == 1) { printf("DCCM double bit error\n"); putchar(DISABLE_ERROR_INJECTION); } else if (mcause == 0x1 && mscause == 0x1 && iccm_test == 1) { printf("ICCM double bit error\n"); putchar(DISABLE_ERROR_INJECTION); } else { printf("Error unrelated to ECC\n"); putchar(TEST_FAILED); } } void run_iccm_err_test(int execute) { uint32_t *iccm_data = (uint32_t *)ICCM_SADDR; uint32_t *iccm = iccm_data; void (* iccm_fn) (void) = (void*)iccm_data; uint32_t *code_word = 0; uint32_t *actual_iccm_code_end = 0; uint32_t mfdc, miccmect; // Inject single bit ICCM error putchar(INJECT_ICCM_SINGLE_BIT); code_word = (uint32_t *) &iccm_start; printf("Copy code from %x [thru %x] to %x\n", (uintptr_t) code_word, &iccm_end, (uintptr_t) iccm); while (code_word < (uint32_t *) &iccm_end) { printf("at %x: %x\n", (uintptr_t) code_word, *code_word); *iccm++ = *code_word++; } putchar(DISABLE_ERROR_INJECTION); if (execute) { iccm_fn(); } mfdc = read_mfdc(); miccmect = read_miccmect(); if ((mfdc & MFDC_DISABLE_ECC_MASK) && (miccmect != 0)) { printf("Unexpected ECC single-bit error detected!\n"); putchar(TEST_FAILED); } else if (!(mfdc & MFDC_DISABLE_ECC_MASK) && (miccmect == 0)) { printf("Did not register expected ECC single-bit error!\n"); putchar(TEST_FAILED); } // Inject double bit ICCM error putchar(INJECT_ICCM_DOUBLE_BIT); code_word = (uint32_t *) &iccm_start; iccm = iccm_data; printf("Copy code from %x [thru %x] to %x\n", (uintptr_t) code_word, &iccm_end, (uintptr_t) iccm); while (code_word < (uint32_t *) &iccm_end) { printf("at %x: %x\n", (uintptr_t) code_word, *code_word); *iccm++ = *code_word++; } putchar(DISABLE_ERROR_INJECTION); if (execute) { iccm_fn(); } } void run_dccm_err_test(void) { uint32_t *dccm_data = (uint32_t *)DCCM_SADDR; uint32_t *dccm = dccm_data; uint32_t mfdc, mdccmect; // Inject single bit DCCM error putchar(INJECT_DCCM_SINGLE_BIT); *dccm = 0x12345678; putchar(DISABLE_ERROR_INJECTION); printf("DCCM value: 0x%x\n", *dccm); mfdc = read_mfdc(); mdccmect = read_mdccmect(); if ((mfdc & MFDC_DISABLE_ECC_MASK) && (mdccmect != 0)) { printf("Unexpected ECC single-bit error detected!\n"); putchar(TEST_FAILED); } else if (!(mfdc & MFDC_DISABLE_ECC_MASK) && (mdccmect == 0)) { printf("Did not register expected ECC single-bit error!\n"); putchar(TEST_FAILED); } // Inject double bit DCCM error putchar(INJECT_DCCM_DOUBLE_BIT); *dccm = 0xDEADBEEF; putchar(DISABLE_ERROR_INJECTION); printf("DCCM value: 0x%x\n", *dccm); } void execute_from_iccm (void) { printf("Executed from ICCM!\n"); } void main(void) { boot_count++; printf("------------------------\n"); printf("Test ECC error injection\n"); printf("------------------------\n\n"); printf("Boot count: %d\n", boot_count); if (boot_count == 1) { iccm_test = 0; dccm_test = 1; printf("Disable ECC checks\n\n"); disable_ecc_check(); run_dccm_err_test(); printf("\nEnable ECC checks\n\n"); enable_ecc_check(); run_dccm_err_test(); // Should not reach here if ECC error is triggerred correctly printf("Did not hit ECC error when expected!\n"); putchar(TEST_FAILED); } else if (boot_count == 2) { iccm_test = 1; dccm_test = 0; printf("Disable ECC checks\n\n"); disable_ecc_check(); // Inject errors without executing due to disabled error correction run_iccm_err_test(0); printf("\nEnable ECC checks\n\n"); enable_ecc_check(); run_iccm_err_test(1); // Should not reach here if ECC error is triggerred correctly printf("Did not hit ECC error when expected!\n"); putchar(TEST_FAILED); } else if (boot_count == 3) { printf("Finished\n"); } else { printf("Unexpected reset\n"); putchar(TEST_FAILED); } } ================================================ FILE: testbench/tests/ecc/ecc.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text*) } _end = .; /* STDOUT */ . = 0xd0580000; .data.io . : { *(.data.io) } /* DCCM */ . = 0xf0040000; dccm = .; .data : { *(.*data) *(.rodata*) *(.sbss)} .bss : { *(.bss); . = ALIGN(4); } STACK = ALIGN(16) + 0x1000; /* ICCM */ iccm_start = .; .iccm_data0 0xee000000 : AT(iccm_start) { KEEP(*(.iccm_data0)); . = ALIGN(4); } = 0x0000, iccm_end = iccm_start + SIZEOF(.iccm_data0); . = 0xfffffff8; .data.ctl : AT(0xfffffff8) { LONG(0xf0040000); LONG(STACK) } } ================================================ FILE: testbench/tests/ecc/ecc.mki ================================================ OFILES = crt0.o ecc.o printf.o TEST_CFLAGS = -g -O3 ================================================ FILE: testbench/tests/insns/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .section .text.init .global _start _start: # Setup stack la sp, STACK # Setup trap handler la t0, _trap csrw mtvec, t0 # Setup PMP # Region 0 TOR 0x00000000-0xFFFFFFFF RWX li t0, 0xFFFFFFFF csrw pmpaddr0, t0 li t0, 0x0000000F csrw pmpcfg0, t0 # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr _trap: # Push stuff addi sp, sp, -17*4 sw ra, 0*4(sp) sw a0, 1*4(sp) sw a1, 2*4(sp) sw a2, 3*4(sp) sw a3, 4*4(sp) sw a4, 5*4(sp) sw a5, 6*4(sp) sw a6, 7*4(sp) sw a7, 8*4(sp) sw t0, 9*4(sp) sw t1, 10*4(sp) sw t2, 11*4(sp) sw t3, 12*4(sp) sw t4, 13*4(sp) sw t5, 14*4(sp) sw t6, 15*4(sp) call trap_handler # Advance mepc if the cause is not an external interrupt csrr t0, mcause li t1, 0x80000000 and t0, t0, t1 bne t0, x0, _is_irq csrr t0, mepc addi t0, t0, 4 csrw mepc, t0 _is_irq: # Pop stuff lw ra, 0*4(sp) lw a0, 1*4(sp) lw a1, 2*4(sp) lw a2, 3*4(sp) lw a3, 4*4(sp) lw a4, 5*4(sp) lw a5, 6*4(sp) lw a6, 7*4(sp) lw a7, 8*4(sp) lw t0, 9*4(sp) lw t1, 10*4(sp) lw t2, 11*4(sp) lw t3, 12*4(sp) lw t4, 13*4(sp) lw t5, 14*4(sp) lw t6, 15*4(sp) addi sp, sp, 17*4 mret .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/insns/insns.c ================================================ #include #define read_csr(csr) ({ \ unsigned long res; \ asm volatile ("csrr %0, " #csr : "=r"(res)); \ res; \ }) #define write_csr(csr, val) { \ asm volatile ("csrw " #csr ", %0" : : "r"(val)); \ } #define MISA_U (1 << 20) #define do_ecall() asm volatile ("ecall") #define do_ebreak() asm volatile ("ebreak\nnop") // EBREAK can translate to C.EBREAK. Insert a nop to align to 4 #define do_wfi() asm volatile ("wfi") #define do_sret() asm volatile ("sret") #define do_mret() asm volatile ("mret") #define is_ecall(x) ((x) == 0x00000073) #define is_ebreak(x) ((x) == 0x00100073 || ((x) & 0xFFFF) == 0x9002) // EBREAK or C.EBREAK #define is_wfi(x) ((x) == 0x10500073) #define is_sret(x) ((x) == 0x10200073) #define is_mret(x) ((x) == 0x30200073) struct trap_info_t { uint32_t mcause; uint32_t insn; }; volatile struct trap_info_t trap_info; void trap_handler () { uint32_t mstatus = read_csr(mstatus); uint32_t mepc = read_csr(mepc); trap_info.mcause = read_csr(mcause); trap_info.insn = *((uint32_t*)mepc); printf("trap! mstatus=0x%08X, mcause=0x%08X, mepc=0x%08X, insn=0x%08X\n", mstatus, trap_info.mcause, mepc, trap_info.insn); } void clear_trap () { trap_info.mcause = 0x00; trap_info.insn = 0x00; } volatile int global_result = 1; // Success void check (int cond) { if (cond) { printf("pass\n"); } else { printf("fail\n"); global_result = 0; } } void user_main (); int main () { printf("Hello VeeR\n"); // The test requires user mode support if ((read_csr(misa) & MISA_U) == 0) { printf("ERROR: The test requires user mode support. Aborting.\n"); return -1; } // Do EBREAK printf("testing EBREAK\n"); clear_trap(); do_ebreak(); check(trap_info.mcause == 0x3 && is_ebreak(trap_info.insn)); // Do ECALL printf("testing ECALL\n"); clear_trap(); do_ecall(); check(trap_info.mcause == 0xb && is_ecall(trap_info.insn)); // Do WFI printf("testing WFI\n"); clear_trap(); do_wfi(); check(!trap_info.mcause); // No trap expected // Do SRET printf("testing SRET\n"); clear_trap(); do_sret(); check(trap_info.mcause == 0x2 && is_sret(trap_info.insn)); // Do not test MRET here. It is going to be used to go to user mode later // anyways. // Go to user mode unsigned long mstatus = read_csr(mstatus); mstatus &= ~(3 << 11); // MPP = 00 (user) mstatus &= ~(1 << 17); // MPRV = 0 write_csr(mstatus, mstatus); void* ptr = (void*)user_main; write_csr(mepc, (unsigned long)ptr); asm volatile ("mret"); return 0; } __attribute__((noreturn)) void user_main () { printf("Hello from user_main()\n"); // Do EBREAK printf("testing EBREAK\n"); clear_trap(); do_ebreak(); check(trap_info.mcause == 0x3 && is_ebreak(trap_info.insn)); // Do ECALL printf("testing ECALL\n"); clear_trap(); do_ecall(); check(trap_info.mcause == 0x8 && is_ecall(trap_info.insn)); // Do WFI printf("testing WFI\n"); clear_trap(); do_wfi(); check(!trap_info.mcause); // No trap expected // Do SRET printf("testing SRET\n"); clear_trap(); do_sret(); check(trap_info.mcause == 0x2 && is_sret(trap_info.insn)); // Do MRET printf("testing MRET\n"); clear_trap(); do_mret(); check(trap_info.mcause == 0x2 && is_mret(trap_info.insn)); // Terminate the simulation // set the exit code to 0xFF or 0x1 and jump to _finish. unsigned char res = (global_result) ? 0xFF : 1; asm volatile ( "mv a0, %0\n" "j _finish\n" : : "r"(res) ); while (1); // Make compiler not complain } ================================================ FILE: testbench/tests/insns/insns.ld ================================================ /* SPDX-License-Identifier: Apache-2.0 */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; .text : { *(.text.init*) *(.text*) } _end = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/tests/insns/insns.mki ================================================ # SPDX-License-Identifier: Apache-2.0 OFILES = crt0.o insns.o printf.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/tests/irq/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .option norvc .option nopic .section .text.init .align 4 .global _start _start: # Setup stack la sp, STACK # Setup trap handler la t0, _trap csrw mtvec, t0 # Setup PMP # Region 0 TOR 0x00000000-0xFFFFFFFF RWX li t0, 0xFFFFFFFF csrw pmpaddr0, t0 li t0, 0x0000000F csrw pmpcfg0, t0 # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr .align 4 _trap: # Push stuff addi sp, sp, -17*4 sw ra, 0*4(sp) sw a0, 1*4(sp) sw a1, 2*4(sp) sw a2, 3*4(sp) sw a3, 4*4(sp) sw a4, 5*4(sp) sw a5, 6*4(sp) sw a6, 7*4(sp) sw a7, 8*4(sp) sw t0, 9*4(sp) sw t1, 10*4(sp) sw t2, 11*4(sp) sw t3, 12*4(sp) sw t4, 13*4(sp) sw t5, 14*4(sp) sw t6, 15*4(sp) call trap_handler # Advance mepc if the cause is not an external interrupt csrr t0, mcause li t1, 0x80000000 and t0, t0, t1 bne t0, x0, _is_irq csrr t0, mepc addi t0, t0, 4 csrw mepc, t0 _is_irq: # Pop stuff lw ra, 0*4(sp) lw a0, 1*4(sp) lw a1, 2*4(sp) lw a2, 3*4(sp) lw a3, 4*4(sp) lw a4, 5*4(sp) lw a5, 6*4(sp) lw a6, 7*4(sp) lw a7, 8*4(sp) lw t0, 9*4(sp) lw t1, 10*4(sp) lw t2, 11*4(sp) lw t3, 12*4(sp) lw t4, 13*4(sp) lw t5, 14*4(sp) lw t6, 15*4(sp) addi sp, sp, 17*4 mret .section .text.nmi .align 4 _nmi: # Push stuff addi sp, sp, -17*4 sw ra, 0(sp) sw a0, 1*4(sp) sw a1, 2*4(sp) sw a2, 3*4(sp) sw a3, 4*4(sp) sw a4, 5*4(sp) sw a5, 6*4(sp) sw a6, 7*4(sp) sw a7, 8*4(sp) sw t0, 9*4(sp) sw t1, 10*4(sp) sw t2, 11*4(sp) sw t3, 12*4(sp) sw t4, 13*4(sp) sw t5, 14*4(sp) sw t6, 15*4(sp) call nmi_handler # Pop stuff lw ra, 0*4(sp) lw a0, 1*4(sp) lw a1, 2*4(sp) lw a2, 3*4(sp) lw a3, 4*4(sp) lw a4, 5*4(sp) lw a5, 6*4(sp) lw a6, 7*4(sp) lw a7, 8*4(sp) lw t0, 9*4(sp) lw t1, 10*4(sp) lw t2, 11*4(sp) lw t3, 12*4(sp) lw t4, 13*4(sp) lw t5, 14*4(sp) lw t6, 15*4(sp) addi sp, sp, 17*4 mret .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/irq/irq.c ================================================ #include #include // ============================================================================ #define read_csr(csr) ({ \ unsigned long res; \ asm volatile ("csrr %0, " #csr : "=r"(res)); \ res; \ }) #define write_csr(csr, val) { \ asm volatile ("csrw " #csr ", %0" : : "r"(val)); \ } #define MISA_U (1 << 20) #define MSTATUS_MPP_MASK (3 << 11) #define MSTATUS_MPP_MACHINE (3 << 11) #define MSTATUS_MPP_USER (0 << 11) #define MSTATUS_MPP_MPRV (1 << 17) #define MSTATUS_MIE (1 << 3) #define MSTATUS_MPIE (1 << 7) #define MIE_MEIE (1 << 11) #define MIE_MTIE (1 << 7) #define MIE_MSIE (1 << 3) #define MCAUSE_NMI 0x0 #define MCAUSE_TIMER_M 0x80000007 #define MCAUSE_SOFTINT_M 0x80000003 #define TEST_RESULT_SUCCESS 0xFF #define TEST_RESULT_FAILURE 1 // ============================================================================ #define CMD_EXT_IRQ_CLR 0x80 #define CMD_EXT_IRQ_SET 0x81 #define CMD_CORE_IRQ_CLR 0x82 #define CMD_CORE_IRQ_SET 0x83 #define CMD_IRQ_CLR_ALL 0x90 #define CORE_IRQ_NMI (1 << 8) #define CORE_IRQ_TIMER (2 << 8) #define CORE_IRQ_SOFT (4 << 8) extern uint32_t tohost; void trigger_nmi_irq (int state) { uint32_t cmd = (state) ? CMD_CORE_IRQ_SET : CMD_CORE_IRQ_CLR; tohost = cmd | CORE_IRQ_NMI; } void trigger_timer_irq (int state) { uint32_t cmd = (state) ? CMD_CORE_IRQ_SET : CMD_CORE_IRQ_CLR; tohost = cmd | CORE_IRQ_TIMER; } void trigger_soft_irq (int state) { uint32_t cmd = (state) ? CMD_CORE_IRQ_SET : CMD_CORE_IRQ_CLR; tohost = cmd | CORE_IRQ_SOFT; } void trigger_ext_irq (int state, int irq) { uint32_t cmd = (state) ? CMD_EXT_IRQ_SET : CMD_EXT_IRQ_CLR; tohost = cmd | (irq << 8); } void release_all_irqs () { tohost = CMD_IRQ_CLR_ALL; } // ============================================================================ struct trap_data_t { uint32_t mcause; uint32_t mstatus; }; volatile struct trap_data_t trap_data[32]; volatile uint32_t trap_count = 0; void trap_handler () { uint32_t mstatus = read_csr(mstatus); uint32_t mcause = read_csr(mcause); uint32_t mepc = read_csr(mepc); // Release interrupt lines release_all_irqs(); printf("trap! mstatus=0x%08X, mcause=0x%08X, mepc=0x%08X\n", mstatus, mcause, mepc); // Store trap data if (trap_count < (sizeof(trap_data) / sizeof(trap_data[0]))) { trap_data[trap_count].mcause = mcause; trap_data[trap_count].mstatus = mstatus; trap_count++; } } void nmi_handler () { // Handle NMIs as regular traps. For purpose of this test it is sufficient trap_handler(); } // ============================================================================ void user_main (); int main () { printf("Hello VeeR\n"); // Enable interrupts unsigned long mie = read_csr(mie); mie |= MIE_MEIE | MIE_MTIE | MIE_MSIE; write_csr(mie, mie); // .............................. // Set mstatus.MIE to 0. This should disable interrupts in M mode printf("Machine mode, MIE=0\n"); unsigned long mstatus = read_csr(mstatus); mstatus &= ~MSTATUS_MIE; write_csr(mstatus, mstatus); // NMI trigger_nmi_irq(1); printf(" NMI triggered\n"); // Timer IRQ trigger_timer_irq(1); printf(" timer irq triggered\n"); // Soft IRQ trigger_soft_irq(1); printf(" soft IRQ triggered\n"); // No exceptions should have occurred // Release interrupt lines release_all_irqs(); // .............................. // Set mstatus.MIE to 1. This should enable interrupts in M mode printf("Machine mode, MIE=1\n"); mstatus = read_csr(mstatus); mstatus |= MSTATUS_MIE; write_csr(mstatus, mstatus); // NMI trigger_nmi_irq(1); printf(" NMI triggered\n"); // Timer IRQ trigger_timer_irq(1); printf(" timer irq triggered\n"); // Soft IRQ trigger_soft_irq(1); printf(" soft IRQ triggered\n"); // Exceptions should have occurred and got recorded. // Release interrupt lines release_all_irqs(); // .............................. // User mode not supported if ((read_csr(misa) & MISA_U) == 0) { printf("WARNING: User mode not supported\n"); // Report traps printf("traps taken: %d\n", trap_count); for (unsigned long i=0; i #include #define read_csr(csr) ({ \ unsigned long res; \ asm volatile ("csrr %0, " #csr : "=r"(res)); \ res; \ }) #define write_csr(csr, val) { \ asm volatile ("csrw " #csr ", %0" : : "r"(val)); \ } #define MISA_U (1 << 20) #define MSTATUS_MPRV (1 << 17) #define MSTATUS_MPP_MASK (3 << 11) #define MSTATUS_MPP_MACHINE (3 << 11) #define MSTATUS_MPP_USER (0 << 11) #define MCAUSE_ECALL_U 0x8 #define MCAUSE_ECALL_M 0xb extern int32_t do_ecall (uint32_t cmd, uint32_t arg); #define ECALL_HELLO 0x10 #define ECALL_CLR_MPRV 0x20 #define ECALL_SET_MPRV 0x21 #define ECALL_GET_MSTATUS 0x30 struct trap_data_t { uint32_t mcause; uint32_t mstatus; }; struct trap_data_t trap_data[32]; uint32_t trap_count = 0; volatile int32_t global_fail = 0; int32_t trap_handler (uint32_t cmd, uint32_t arg) { unsigned long mstatus = read_csr(mstatus); unsigned long mcause = read_csr(mcause); unsigned long mepc = read_csr(mepc); // Store trap data if (trap_count < (sizeof(trap_data) / sizeof(trap_data[0]))) { trap_data[trap_count].mcause = mcause; trap_data[trap_count].mstatus = mstatus; trap_count++; } printf("trap! mstatus=0x%08X, mcause=0x%08X, mepc=0x%08X\n", mstatus, mcause, mepc); // Handle ecall if (mcause == MCAUSE_ECALL_U || mcause == MCAUSE_ECALL_M) { printf("Hello ECALL.%c\n", (mcause == MCAUSE_ECALL_U) ? 'U' : (mcause == MCAUSE_ECALL_M) ? 'M' : '?'); if (cmd == ECALL_HELLO) { return 0; } if (cmd == ECALL_CLR_MPRV) { printf(" clearing mstatus.MPRV\n"); mstatus &= ~MSTATUS_MPRV; write_csr(mstatus, mstatus); return mstatus; } if (cmd == ECALL_SET_MPRV) { printf(" setting mstatus.MPRV\n"); mstatus |= MSTATUS_MPRV; write_csr(mstatus, mstatus); return mstatus; } if (cmd == ECALL_GET_MSTATUS) { return mstatus; } printf(" unknown ECALL code 0x%08X !\n", cmd); return -1; } return 0; // Ignored } void user_main (); int main () { // The test requires user mode support if ((read_csr(misa) & MISA_U) == 0) { printf("ERROR: The test requires user mode support. Aborting.\n"); return -1; } uint32_t mstatus = read_csr(mstatus); // main() gets called from _start. We should be in machine mode. printf("Hello VeeR\n"); // Verify initial state of mstatus after reset if (!(mstatus & MSTATUS_MPRV)) { printf("[ OK ] MPRV cleared\n"); } else { printf("[ FAIL ] MPRV is set!\n"); global_fail = 1; } // Check if MPP is set to 11 if ((mstatus & MSTATUS_MPP_MASK) == MSTATUS_MPP_MACHINE) { printf("[ OK ] MPP is 11\n"); } else { printf("[ FAIL ] MPP is not 11\n"); global_fail = 1; } // Clear MPRV, make an ECALL which should set mcause to 11 (0xB) and // leave MPRV mstatus = read_csr(mstatus); mstatus &= ~MSTATUS_MPRV; write_csr(mstatus, mstatus); printf("doing ECALL (MPRV=0)...\n"); do_ecall(ECALL_HELLO, 0); // Check if MPRV is cleared mstatus = read_csr(mstatus); if (!(mstatus & MSTATUS_MPRV)) { printf("[ OK ] MPRV cleared\n"); } else { printf("[ FAIL ] MPRV is set!\n"); global_fail = 1; } // Check if MPP is set to 00 if ((mstatus & MSTATUS_MPP_MASK) == MSTATUS_MPP_USER) { printf("[ OK ] MPP is 00\n"); } else { printf("[ FAIL ] MPP is not 00\n"); global_fail = 1; } // Set MPRV and do the ECALL again mstatus = read_csr(mstatus); mstatus |= MSTATUS_MPRV; write_csr(mstatus, mstatus); printf("doing ECALL (MPRV=1)\n"); do_ecall(ECALL_HELLO, 0); // Check if MPRV is set mstatus = read_csr(mstatus); if (mstatus & MSTATUS_MPRV) { printf("[ OK ] MPRV is set\n"); } else { printf("[ FAIL ] MPRV is cleared!\n"); global_fail = 1; } // Check if MPP is set to 00 if ((mstatus & MSTATUS_MPP_MASK) == MSTATUS_MPP_USER) { printf("[ OK ] MPP is 00\n"); } else { printf("[ FAIL ] MPP is not 00\n"); global_fail = 1; } // Go to user mode, clear MPRV mstatus = read_csr(mstatus); mstatus &= ~MSTATUS_MPP_MASK; mstatus &= ~MSTATUS_MPRV; write_csr(mstatus, mstatus); void* ptr = (void*)user_main; write_csr(mepc, (unsigned long)ptr); asm volatile ("mret"); return 0; } __attribute__((noreturn)) void user_main () { uint32_t mstatus; // We should be now in user mode printf("Hello from user_main()\n"); // Do an ECALL to clear MPRV printf("doing ECALL...\n"); mstatus = do_ecall(ECALL_CLR_MPRV, 0); // ECALL returns mstatus value right before returning to user mode. // Check if MPP is set to 00 as we called from user mode if ((mstatus & MSTATUS_MPP_MASK) == MSTATUS_MPP_USER) { printf("[ OK ] MPP is 00\n"); } else { printf("[ FAIL ] MPP is not 00\n"); global_fail = 1; } // Do an ECALL to get mstatus printf("doing ECALL...\n"); mstatus = do_ecall(ECALL_GET_MSTATUS, 0); // Check if MPRV was cleared if (!(mstatus & MSTATUS_MPRV)) { printf("[ OK ] MPRV was cleared\n"); } else { printf("[ FAIL ] MPRV was set!\n"); global_fail = 1; } // Do an ECALL to set MPRV printf("doing ECALL...\n"); mstatus = do_ecall(ECALL_SET_MPRV, 0); // ECALL returns mstatus value right before returning to user mode. // Check if MPP is set to 00 as we called from user mode if ((mstatus & MSTATUS_MPP_MASK) == MSTATUS_MPP_USER) { printf("[ OK ] MPP is 00\n"); } else { printf("[ FAIL ] MPP is not 00\n"); global_fail = 1; } // Do an ECALL to get mstatus printf("doing ECALL...\n"); mstatus = do_ecall(ECALL_GET_MSTATUS, 0); // Check if MPRV was cleared if (!(mstatus & MSTATUS_MPRV)) { printf("[ OK ] MPRV was cleared\n"); } else { printf("[ FAIL ] MPRV was set!\n"); global_fail = 1; } // Verify trap data unsigned char res = 0xFF; printf("traps taken:\n"); for (unsigned long i=0; i #include #include // Clear the destination reg before reading so that when the read fails the // returned value is 0 #define read_csr(csr) ({ \ unsigned long res; \ asm volatile ( \ "li %0, 0\n" \ "csrr %0, %1" \ : "=r"(res) : "i"(csr) \ ); \ res; \ }) #define write_csr(csr, val) { \ asm volatile ("csrw %0, %1" : : "i"(csr), "r"(val)); \ } #define MISA_U (1 << 20) #define CSR_MISA 0x301 #define CSR_MSTATUS 0x300 #define CSR_MCAUSE 0x342 #define CSR_MEPC 0x341 #define CSR_MCOUNTEREN 0x306 #define CSR_CYCLE 0xC00 #define CSR_CYCLEH 0xC80 #define CSR_INSTRET 0xC02 #define CSR_INSTRETH 0xC82 #define CSR_HPMCOUNTER3 0xC03 #define CSR_HPMCOUNTER3H 0xC83 #define CSR_HPMCOUNTER4 0xC04 #define CSR_HPMCOUNTER4H 0xC84 #define CSR_HPMCOUNTER5 0xC05 #define CSR_HPMCOUNTER5H 0xC85 #define CSR_HPMCOUNTER6 0xC06 #define CSR_HPMCOUNTER6H 0xC86 #define CSR_MHPMEVENT3 0x323 #define CSR_MHPMEVENT4 0x324 #define CSR_MHPMEVENT5 0x325 #define CSR_MHPMEVENT6 0x326 #define ECALL_GET_MCOUNTEREN 0x10 #define ECALL_SET_MCOUNTEREN 0x20 #define MSTATUS_MPP_MASK (3 << 11) #define MSTATUS_MPRV (1 << 17) #define MCAUSE_ILLEGAL_INSTR 0x2 #define MCAUSE_ECALL_U 0x8 #define MCAUSE_ECALL_M 0xb #define MCOUNTEREN_CY (1 << 0) #define MCOUNTEREN_IR (1 << 2) #define MCOUNTEREN_HPM3 (1 << 3) #define MCOUNTEREN_HPM4 (1 << 4) #define MCOUNTEREN_HPM5 (1 << 5) #define MCOUNTEREN_HPM6 (1 << 6) #define MCOUNTEREN_ALL 0x7D #define MCOUNTEREN_NONE 0x00 #define TEST_RESULT_SUCCESS 0xFF #define TEST_RESULT_FAILURE 1 #define VEER_EVT_INSTR_COMMITTED_16 5 #define VEER_EVT_INSTR_COMMITTED_32 6 #define VEER_EVT_BRANCHES_COMMITTED 24 #define VEER_EVT_BRANCHES_MISPREDICTED 25 #define COUNTER_COUNT 6 volatile int32_t global_result = 0; volatile uint32_t last_trap = 0xFFFFFFFF; int32_t do_ecall (uint32_t cmd, uint32_t arg); int32_t ecall_handler (uint32_t cmd, uint32_t arg) { if (cmd == ECALL_GET_MCOUNTEREN) { return read_csr(CSR_MCOUNTEREN); } if (cmd == ECALL_SET_MCOUNTEREN) { printf("set mcounteren=0x%08X\n", arg); write_csr(CSR_MCOUNTEREN, arg); return 0; } printf("unknown ECALL code 0x%08X\n", cmd); global_result = -1; return -1; } int32_t trap_handler (uint32_t a0, uint32_t a1) { uint32_t mstatus = read_csr(CSR_MSTATUS); uint32_t mcause = read_csr(CSR_MCAUSE); printf("trap! mstatus=0x%08X, mcause=0x%08X\n", mstatus, mcause); // Handle ECALL if (mcause == MCAUSE_ECALL_U || mcause == MCAUSE_ECALL_M) { return ecall_handler(a0, a1); } // Store mcause code last_trap = mcause; return 0; } void user_main (); int main () { printf("\nHello VeeR\n"); // The test requires user mode support if ((read_csr(CSR_MISA) & MISA_U) == 0) { printf("ERROR: The test requires user mode support. Aborting.\n"); return -1; } // Setup VeeR performance counter events. See VeeR EL2 manual table 7-1 // for the complete event list and their codes. write_csr(CSR_MHPMEVENT3, VEER_EVT_INSTR_COMMITTED_16); write_csr(CSR_MHPMEVENT4, VEER_EVT_INSTR_COMMITTED_32); write_csr(CSR_MHPMEVENT5, VEER_EVT_BRANCHES_COMMITTED); write_csr(CSR_MHPMEVENT6, VEER_EVT_BRANCHES_MISPREDICTED); // Write mcounteren to allow counter access from user_mode write_csr(CSR_MCOUNTEREN, MCOUNTEREN_ALL); // Go to user mode uint32_t mstatus = read_csr(CSR_MSTATUS); mstatus &= ~MSTATUS_MPP_MASK; // MPP = 00 (user) mstatus &= ~MSTATUS_MPRV; // MPRV = 0 write_csr(CSR_MSTATUS, mstatus); void* ptr = (void*)user_main; write_csr(CSR_MEPC, (unsigned long)ptr); asm volatile ("mret"); return 0; } const char* get_csr_name (int32_t csr) { switch (csr) { case CSR_CYCLE: return "cycle"; case CSR_CYCLEH: return "cycleh"; case CSR_INSTRET: return "instret"; case CSR_INSTRETH: return "instreth"; case CSR_HPMCOUNTER3: return "hpmcounter3"; case CSR_HPMCOUNTER3H: return "hpmcounter3h"; case CSR_HPMCOUNTER4: return "hpmcounter4"; case CSR_HPMCOUNTER4H: return "hpmcounter4h"; case CSR_HPMCOUNTER5: return "hpmcounter5"; case CSR_HPMCOUNTER5H: return "hpmcounter5h"; case CSR_HPMCOUNTER6: return "hpmcounter6"; case CSR_HPMCOUNTER6H: return "hpmcounter6h"; } return ""; } uint32_t read_and_check (int32_t csr, int should_succeed) { // Clear trap code last_trap = 0xFFFFFFFF; // Read the CSR of interest uint32_t val = 0; switch (csr) { case CSR_CYCLE: val = read_csr(CSR_CYCLE); break; case CSR_CYCLEH: val = read_csr(CSR_CYCLEH); break; case CSR_INSTRET: val = read_csr(CSR_INSTRET); break; case CSR_INSTRETH: val = read_csr(CSR_INSTRETH); break; case CSR_HPMCOUNTER3: val = read_csr(CSR_HPMCOUNTER3); break; case CSR_HPMCOUNTER3H: val = read_csr(CSR_HPMCOUNTER3H); break; case CSR_HPMCOUNTER4: val = read_csr(CSR_HPMCOUNTER4); break; case CSR_HPMCOUNTER4H: val = read_csr(CSR_HPMCOUNTER4H); break; case CSR_HPMCOUNTER5: val = read_csr(CSR_HPMCOUNTER5); break; case CSR_HPMCOUNTER5H: val = read_csr(CSR_HPMCOUNTER5H); break; case CSR_HPMCOUNTER6: val = read_csr(CSR_HPMCOUNTER6); break; case CSR_HPMCOUNTER6H: val = read_csr(CSR_HPMCOUNTER6H); break; } // Check if (should_succeed) { if (last_trap != 0xFFFFFFFF) { printf("[ FAILED ] %s access should succeed, but trap encountered\n", get_csr_name(csr)); global_result = -1; return 0; } } else { if (last_trap != MCAUSE_ILLEGAL_INSTR) { // Illegal instruction if (last_trap == 0xFFFFFFFF) { printf("[ FAILED ] %s access should fail, but no trap encountered\n", get_csr_name(csr)); } else { printf("[ FAILED ] %s access should fail, but with different mcause code\n", get_csr_name(csr)); } global_result = -1; return 0; } } printf("[ OK ] %s = %d\n", get_csr_name(csr), val); return val; } uint64_t read_and_check64(int32_t csr_base, int should_succeed) { // CSRs for high 32-bit parts of counters have the same addresses but // logically or-ed with 0x80. uint32_t hi = read_and_check(csr_base | 0x80, should_succeed); uint32_t lo = read_and_check(csr_base, should_succeed); return (((uint64_t)hi) << 32) | lo; } void check_counters (const uint64_t* cur_counters) { const char* counter_names[COUNTER_COUNT] = { "cycle ", "instret", "hpm3 ", "hpm4 ", "hpm5 ", "hpm6 " }; static uint64_t prv_counters [COUNTER_COUNT] = {0}; // Compute and print diffs int counters_ok = 1; for (int i=0; i * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include extern volatile char tohost; __attribute__((__noreturn__)) void _exit (int status) { if (!status) tohost = 0xff; else tohost = 0x01; while (1) {}; } int veer_tb_putc(char c, FILE *stream) { (void) stream; tohost = c; return c; } static FILE __stdio = FDEV_SETUP_STREAM(veer_tb_putc, NULL, NULL, _FDEV_SETUP_WRITE); FILE *const stdin = &__stdio; __strong_reference(stdin, stdout); __strong_reference(stdin, stderr); ================================================ FILE: testbench/tests/pmp/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .option norvc .option nopic .section .text.init .align 4 .global _start _start: # Setup stack la sp, _stack_hi # Setup trap handler la t0, _trap_entry csrw mtvec, t0 # Clear .bss la t0, _bss la t1, _data_end bss: sw x0, 0(t0) addi t0, t0, 4 bne t0, t1, bss # Call main() call main # Map exit code: 0 - success, not 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination, a0 holds the exit code beq x0, x0, _finish .rept 10 nop .endr .align 8 _trap_entry: # Push one reg addi sp, sp, -4 sw t0, 0(sp) # Check for ECALL.U csrr t0, mcause addi t0, t0, -8 bnez t0, _trap_not_ecall_u # Pop one reg lw t0, 0(sp) addi sp, sp, +4 # "return" to the ucall j _ucall_ret _trap_not_ecall_u: # Pop one reg # FIXME: Integrate pushing and popping lw t0, 0(sp) addi sp, sp, +4 # Push stuff addi sp, sp, -35*4 # (32 regs + 3 CSRs) sw x0 , 0*4(sp) sw x1 , 1*4(sp) sw x2 , 2*4(sp) sw x3 , 3*4(sp) sw x4 , 4*4(sp) sw x5 , 5*4(sp) sw x6 , 6*4(sp) sw x7 , 7*4(sp) sw x8 , 8*4(sp) sw x9 , 9*4(sp) sw x10, 10*4(sp) sw x11, 11*4(sp) sw x12, 12*4(sp) sw x13, 13*4(sp) sw x14, 14*4(sp) sw x15, 15*4(sp) sw x16, 16*4(sp) sw x17, 17*4(sp) sw x18, 18*4(sp) sw x19, 19*4(sp) sw x20, 20*4(sp) sw x21, 21*4(sp) sw x22, 22*4(sp) sw x23, 23*4(sp) sw x24, 24*4(sp) sw x25, 25*4(sp) sw x26, 26*4(sp) sw x27, 27*4(sp) sw x28, 28*4(sp) sw x29, 29*4(sp) sw x30, 30*4(sp) sw x31, 31*4(sp) # push CSRs csrr t0, mepc sw t0, 32*4(sp) csrr t0, mcause sw t0, 33*4(sp) csrr t0, mtval sw t0, 34*4(sp) # Make a0 point to the stack frame which layout matches the fault struct mv a0, sp # Call trap handler call trap_handler # Advance mepc if the cause is not an external interrupt lw t0, 33*4(sp) li t1, 0x80000000 and t0, t0, t1 bne t0, x0, _trap_is_irq csrr t0, mepc addi t0, t0, 4 csrw mepc, t0 _trap_is_irq: # Pop stuff lw x0 , 0*4(sp) lw x1 , 1*4(sp) lw x2 , 2*4(sp) lw x3 , 3*4(sp) lw x4 , 4*4(sp) lw x5 , 5*4(sp) lw x6 , 6*4(sp) lw x7 , 7*4(sp) lw x8 , 8*4(sp) lw x9 , 9*4(sp) lw x10, 10*4(sp) lw x11, 11*4(sp) lw x12, 12*4(sp) lw x13, 13*4(sp) lw x14, 14*4(sp) lw x15, 15*4(sp) lw x16, 16*4(sp) lw x17, 17*4(sp) lw x18, 18*4(sp) lw x19, 19*4(sp) lw x20, 20*4(sp) lw x21, 21*4(sp) lw x22, 22*4(sp) lw x23, 23*4(sp) lw x24, 24*4(sp) lw x25, 25*4(sp) lw x26, 26*4(sp) lw x27, 27*4(sp) lw x28, 28*4(sp) lw x29, 29*4(sp) lw x30, 30*4(sp) lw x31, 31*4(sp) addi sp, sp, 35*4 # Return mret .section .text .global ucall ucall: # Prologue addi sp, sp, -4*4 sw ra, 0*4(sp) sw s0, 1*4(sp) sw s1, 2*4(sp) # Clear mstatus MPP csrr s0, mstatus li s1, 0xFFFFE7FF and s0, s0, s1 csrw mstatus, s0 # Set the call vector (first arg) csrw mepc, a0 # Store the return address to proxy code in ra la ra, _ucall_proxy # Shift arguments a[n] <- a[n+1] mv a0, a1 mv a1, a2 mv a2, a3 mv a3, a4 mv a4, a5 mv a5, a6 mv a6, a7 li a7, 0 # Jump mret _ucall_ret: # Epilogue lw ra, 0*4(sp) lw s0, 1*4(sp) lw s1, 2*4(sp) addi sp, sp, +4*4 ret _ucall_proxy: ecall .global rv_setjmp_m rv_setjmp_m: # Save PC sw s0, -4(sp) auipc s0, 0 addi s0, s0, -4 sw s0, 0(a0) lw s0, -4(sp) # Save context to the buffer pointed by a0 # the first word is the PC sw x1 , 1*4(a0) sw x2 , 2*4(a0) sw x3 , 3*4(a0) sw x4 , 4*4(a0) sw x5 , 5*4(a0) sw x6 , 6*4(a0) sw x7 , 7*4(a0) sw x8 , 8*4(a0) sw x9 , 9*4(a0) sw x10, 10*4(a0) sw x11, 11*4(a0) sw x12, 12*4(a0) sw x13, 13*4(a0) sw x14, 14*4(a0) sw x15, 15*4(a0) sw x16, 16*4(a0) sw x17, 17*4(a0) sw x18, 18*4(a0) sw x19, 19*4(a0) sw x20, 20*4(a0) sw x21, 21*4(a0) sw x22, 22*4(a0) sw x23, 23*4(a0) sw x24, 24*4(a0) sw x25, 25*4(a0) sw x26, 26*4(a0) sw x27, 27*4(a0) sw x28, 28*4(a0) sw x29, 29*4(a0) sw x30, 30*4(a0) sw x31, 31*4(a0) # Return the exit code set by rv_longjmp if any lw a0, 32*4(a0) ret .global rv_longjmp_m rv_longjmp_m: # Set return address lw s0, 0(a0) csrw mepc, s0 # Set rv_setjmp exit code sw a1, 32*4(a0) # Make sure that we return to M mode csrr s0, mstatus li s1, 0x00001800 or s0, s0, s1 csrw mstatus, s0 # Restore the context to what's pointed by a0 lw x1 , 1*4(a0) lw x2 , 2*4(a0) lw x3 , 3*4(a0) lw x4 , 4*4(a0) lw x5 , 5*4(a0) lw x6 , 6*4(a0) lw x7 , 7*4(a0) lw x8 , 8*4(a0) lw x9 , 9*4(a0) lw x10, 10*4(a0) lw x11, 11*4(a0) lw x12, 12*4(a0) lw x13, 13*4(a0) lw x14, 14*4(a0) lw x15, 15*4(a0) lw x16, 16*4(a0) lw x17, 17*4(a0) lw x18, 18*4(a0) lw x19, 19*4(a0) lw x20, 20*4(a0) lw x21, 21*4(a0) lw x22, 22*4(a0) lw x23, 23*4(a0) lw x24, 24*4(a0) lw x25, 25*4(a0) lw x26, 26*4(a0) lw x27, 27*4(a0) lw x28, 28*4(a0) lw x29, 29*4(a0) lw x30, 30*4(a0) lw x31, 31*4(a0) # Return mret .section .data.io .global tohost tohost: .dword 0 .global fromhost fromhost: .dword 0 ================================================ FILE: testbench/tests/pmp/fault.c ================================================ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2023 Antmicro, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "veer.h" #include "trap.h" #include "fault.h" volatile struct rv_jmp_buf* fault_jmp_env = NULL; volatile struct fault fault_last; void fault_setjmp(struct rv_jmp_buf* env) { fault_jmp_env = env; } struct fault fault_last_get(void) { return fault_last; } void fault_return(const struct fault *fault) { // Save register state for later usage memcpy((struct fault*)&fault_last, fault, sizeof(fault_last)); // Return to program if setjmp-based try-catch was used if (fault_jmp_env != NULL) { struct rv_jmp_buf* env = (struct rv_jmp_buf*)fault_jmp_env; fault_jmp_env = NULL; rv_longjmp_m(env, 1); } } ================================================ FILE: testbench/tests/pmp/fault.h ================================================ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2023 Antmicro, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _FAULT_H #define _FAULT_H #include "veer.h" #include "trap.h" #define EXC_INSTRUCTION_ACC_FAULT 1 #define EXC_LOAD_ACC_FAULT 5 #define EXC_STORE_ACC_FAULT 7 void fault_setjmp(struct rv_jmp_buf* env); struct fault fault_last_get(void); void fault_return(const struct fault *fault); #endif ================================================ FILE: testbench/tests/pmp/main.c ================================================ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2023 Antmicro, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "veer.h" #include "fault.h" #include "pmp.h" #ifndef RV_SMEPMP #define RV_SMEPMP 0 #endif #define CSR_MSTATUS 0x300 #define CSR_MISA 0x301 #define CSR_MEPC 0x341 #define MISA_U (1 << 20) extern uint32_t _text; extern uint32_t _text_end; extern uint32_t _data; extern uint32_t _data_end; extern uint32_t _stack_lo; extern uint32_t _stack_hi; extern uint32_t _area; extern uint32_t tohost; extern int ucall (void* ptr, ...); // ============================================================================ volatile uint32_t test_area [16] __attribute__((section(".area.bufr"))); const uint32_t test_pattern_a [] = { 0xE8C50A2E, 0x017F84CA, 0xFB8A3138, 0xFDF0F930, 0xA5F12034, 0x4A67B7B6, 0xD03C9377, 0xD124A11C, 0xAB319961, 0xF94AF557, 0xDD743AE6, 0xAAB99BC3, 0xE992D7FA, 0x5C6A76FA, 0xD8D63FE2, 0x8616CFC6 }; const uint32_t test_pattern_b [] = { 0x2B0B56F2, 0x6B78B6FF, 0xE7B61C7A, 0x66FB04DB, 0xC2F2BE9D, 0x2D569A89, 0x905BF8E6, 0x2798E7CE, 0x509BA997, 0xBF0147EB, 0x09065BEF, 0x04146267, 0xC421C6E3, 0xD6C76040, 0x773AA931, 0x01C01BDE }; volatile unsigned long did_execute = 0; void __attribute__((noinline)) test_hello () { did_execute = 1; printf(" hello\n"); } int __attribute__((noinline)) test_read (const uint32_t* pattern) { did_execute = 1; printf(" reading from .area...\n"); uint32_t arr[16]; for (size_t i=0; i<16; ++i) { arr[i] = test_area[i]; } if (memcmp(arr, pattern, sizeof(arr))) { printf(" data mismatch\n"); return -1; } else { printf(" data match\n"); } return 0; } void __attribute__((noinline)) test_write (const uint32_t* pattern) { did_execute = 1; printf(" writing to .area...\n"); for (size_t i=0; i<16; ++i) { test_area[i] = pattern[i]; } } void __attribute__((noinline, section(".area.code"))) test_exec () { printf(" hello from .area\n"); } // ============================================================================ volatile unsigned long trap_count = 0; int trap_handler (const struct fault* fault) { printf(" Trap! mcause=0x%08x, mepc=0x%08X, sp=0x%08X\n", fault->mcause, fault->mepc, fault->r[2]); // Terminate the simulation if too many traps got triggered if (++trap_count > 100) { printf("Too many traps, aborting...\n"); _exit(-1); } // If setjmp-based try-catch was used return to the program fault_return(fault); return 0; } // ============================================================================ // Convert byte address for PMP. Effectively does "ceil(x / 4)" #define ADDR2PMP(x) ((((uint32_t)(x)) & 3) ? ((((uint32_t)(x)) >> 2) + 1) : \ (((uint32_t)(x)) >> 2)) // Set mstatus MPRV #define set_mprv(x) { \ uint32_t mstatus; \ CSRR_READ(mstatus, CSR_MSTATUS); \ if (x) mstatus |= (1 << 17); \ else mstatus &= ~(1 << 17); \ CSRR_WRITE(mstatus, CSR_MSTATUS); \ } // Set mstatus MPP to 00 or 11 #define set_mpp(x) { \ uint32_t mstatus; \ CSRR_READ(mstatus, CSR_MSTATUS); \ if (x) mstatus |= (3 << 11); \ else mstatus &= ~(3 << 11); \ CSRR_WRITE(mstatus, CSR_MSTATUS); \ } #define TST_R 1 #define TST_W 2 #define TST_X 4 #define TST_M 16 #define TST_MPRV 32 #define TST_MPP 64 // ============================================================================ int main () { printf("Hello VeeR (M mode)\n"); #if RV_SMEPMP printf("VeeR has Smepmp\n"); #else printf("VeeR does not have Smepmp\n"); #endif // Check if we have user mode support uint32_t misa = 0; CSRR_READ(misa, CSR_MISA); int have_user_mode = (misa & MISA_U) != 0; #if RV_SMEPMP // Set MSECCFG uint32_t mseccfg = 0; CSRR_WRITE(mseccfg, 0x747); #endif // ....................................................................... // Determine PMP granularity uintptr_t tmp = 0; pmp_write_pmpcfg (0, &tmp); tmp = 0xFFFFFFFF; pmp_write_pmpaddr(0, &tmp); pmp_read_pmpaddr (0, &tmp); int g = 0; for (; g < 32; ++g) { if (tmp & 1) break; tmp >>= 1; } printf("PMP G=%d, granularity is %d\n", g, 1 << (g + 2)); // ....................................................................... struct pmp_entry_s entry; int tid = 0; int failed = 0; pmp_clear(); // ....................................................................... // Check if user mode has access to everything by default when PMP is not // configured. Just call a simple function. if (have_user_mode) { printf("%02d - User mode RWX in default state\n", tid++); printf(" testing...\n"); #if RV_SMEPMP TRY { ucall(test_hello); printf(" fail\n"); failed++; } CATCH { printf(" pass\n"); } END_TRY; #else TRY { ucall(test_hello); printf(" pass\n"); } CATCH { printf(" fail\n"); failed++; } END_TRY; #endif } // ....................................................................... // Configure a single region in PMP and call user mode function. It should // not have access to code and stack hence it should not execute if (have_user_mode) { printf("%02d - User mode RWX with one (any) PMP region enabled\n", tid++); // Allow area1 user access entry.addr = ADDR2PMP(&_area); entry.addr = (entry.addr & 0xFFFFFC00) | 0x000001FF; // NAPOT, 2^12 entry.cfg = PMP_NAPOT | PMP_R | PMP_W | PMP_X; pmp_entry_write(5, &entry); printf(" testing...\n"); TRY { ucall(test_hello); printf(" fail\n"); failed++; } CATCH { printf(" pass\n"); } END_TRY; } // ....................................................................... // Configure PMP to allow user mode access to code and stack if (have_user_mode) { printf("%02d - User mode RWX with code, data and stack access allowed\n", tid++); // Allow user access to "tohost" and "fromhost" entry.addr = ADDR2PMP(&tohost); entry.addr = (entry.addr & 0xFFFFFFFC) | 1; // NAPOT 2^4 entry.cfg = PMP_NAPOT | PMP_R | PMP_W; pmp_entry_write(0, &entry); // Allow user access to code entry.addr = ADDR2PMP(&_text); entry.cfg = 0; pmp_entry_write(1, &entry); entry.addr = ADDR2PMP(&_text_end) + 1; // upper bound is not inclusive entry.cfg = PMP_TOR | PMP_R | PMP_X; pmp_entry_write(2, &entry); // Allow user access to data entry.addr = ADDR2PMP(&_data); entry.addr = (entry.addr & 0xFFFFFC00) | 0x000001FF; // NAPOT, 2^12 entry.cfg = PMP_NAPOT | PMP_R | PMP_W; pmp_entry_write(3, &entry); entry.addr = ADDR2PMP(&_data); // Allow user access to stack entry.addr = ADDR2PMP(&_stack_lo); entry.addr = (entry.addr & 0xFFFFF800) | 0x000003FF; // NAPOT, 2^13 entry.cfg = PMP_NAPOT | PMP_R | PMP_W; pmp_entry_write(4, &entry); printf(" testing...\n"); TRY { ucall(test_hello); printf(" pass\n"); } CATCH { printf(" fail\n"); failed++; } END_TRY; } // ....................................................................... // Test PMP operation for all possible RWX combinations in U and M mode. // Generate test cases. A test case is encoded on a byte: // bit 0: R // bit 1: W // bit 2: X // bit 4: 0-user, 1-machine // bit 5: mstatus.MPRV // bit 6: mstatus.MPP (0 for 00, 1 for 11) uint8_t test_cases [32]; uint32_t test_count = 0; // Test cases for all RWX combinations in user mode if (have_user_mode) { for (size_t i=0; i<8; ++i) { uint32_t r = (i & 1) ? PMP_R : 0; uint32_t w = (i & 2) ? PMP_W : 0; uint32_t x = (i & 4) ? PMP_X : 0; #if RV_SMEPMP // Skip -W- and -WX combinations if (!r && w && !x) continue; if (!r && w && x) continue; #endif test_cases[test_count++] = i; } } // Test cases for all RWX combinations in machine mode for (size_t i=0; i<8; ++i) { uint32_t r = (i & 1) ? PMP_R : 0; uint32_t w = (i & 2) ? PMP_W : 0; uint32_t x = (i & 4) ? PMP_X : 0; #if RV_SMEPMP // Skip -W- and -WX combinations if (!r && w && !x) continue; if (!r && w && x) continue; #endif test_cases[test_count++] = TST_M | i; } // Test cases for all RWX combinations in machine mode with MPRV set if (have_user_mode) { for (size_t i=0; i<16; ++i) { uint32_t r = (i & 1) ? PMP_R : 0; uint32_t w = (i & 2) ? PMP_W : 0; uint32_t x = (i & 4) ? PMP_X : 0; uint32_t mpp = (i & 8) != 0; #if RV_SMEPMP // Skip -W- and -WX combinations if (!r && w && !x) continue; if (!r && w && x) continue; #endif test_cases[test_count++] = (TST_MPP * mpp) | TST_MPRV | TST_M | i; } } // ................................ // Do the tests for (size_t i=0; i #include "pmp.h" int pmp_clear () { const int pmp_entries = 16; // FIXME: Parametrize that uintptr_t zero = 0; int res = 0; for (int i=0; i<(pmp_entries + 3)/4; ++i) { if (pmp_write_pmpcfg(i, &zero)) { res = -1; } } for (int i=0; i> 2) & ((__riscv_xlen == 32) ? (~0) : (~1)); unsigned int pmpcfg_id_fine = id & ((__riscv_xlen == 32) ? 3 : 7); uintptr_t pmpcfg_csr; uintptr_t pmpaddr_csr; /* One PMPCFGx register contains configuration * for 4 entries (RV32) or 8 entries (RV64). */ if (!entry) return 1; if (id > 64) return 2; /* Read PMPADDRx CSR */ if (pmp_read_pmpaddr(id, &pmpaddr_csr) != 0) return 3; /* Read PMPCFGx CSR */ if (pmp_read_pmpcfg(pmpcfg_id_coarse, &pmpcfg_csr) != 0) return 4; entry->addr = pmpaddr_csr; entry->cfg = (pmpcfg_csr >> (8 * pmpcfg_id_fine)) & 0xff; return 0; } int pmp_entry_write(unsigned int id, struct pmp_entry_s * entry) { unsigned int pmpcfg_id_coarse = (id >> 2) & ((__riscv_xlen == 32) ? (~0) : (~1)); unsigned int pmpcfg_id_fine = id & ((__riscv_xlen == 32) ? 3 : 7); unsigned int pmpcfg_csr; unsigned int pmpaddr_csr; /* One PMPCFGx register contains configuration * for 4 entries (RV32) or 8 entries (RV64). */ if (!entry) return 1; if (id > 64) return 2; /* Write entry to PMPADDRx CSR */ pmpaddr_csr = entry->addr; if (pmp_write_pmpaddr(id, &pmpaddr_csr) != 0) return 3; /* Write entry to PMPCFGx CSR. Other entries in the same CSR are left intact */ if (pmp_read_pmpcfg(pmpcfg_id_coarse, &pmpcfg_csr) != 0) return 4; pmpcfg_csr = pmpcfg_csr & (~(0xff << (pmpcfg_id_fine * 8))) | (entry->cfg << (pmpcfg_id_fine * 8)); if (pmp_write_pmpcfg(pmpcfg_id_coarse, &pmpcfg_csr) != 0) return 5; return 0; } int pmp_is_cfg_legal (unsigned int cfg) { // Check if RWX combination is legal according to // RISC-V privilege spec v1.12 chapter 3.7.1 cfg &= (PMP_R | PMP_W | PMP_X); if (cfg == (PMP_W)) return 0; if (cfg == (PMP_W | PMP_X)) return 0; return 1; } ================================================ FILE: testbench/tests/pmp/pmp.h ================================================ #include #define PMP_LOCK (1<<7) #define PMP_OFF (0<<3) #define PMP_TOR (1<<3) #define PMP_NA4 (2<<3) #define PMP_NAPOT (3<<3) #define PMP_X (1<<2) #define PMP_W (1<<1) #define PMP_R (1<<0) #define PMP_MODE_MASK (3<<3) #define PMP_RWX_MASK (7) #define CSR_PMPCFG_BASE 0x3A0 #define CSR_PMPADDR_BASE 0x3B0 #define CSRR_READ(v, csr) \ /* CSRR_READ(v, csr): \ * csr: MUST be a compile time integer 12-bit constant (0-4095) \ */ \ __asm__ __volatile__ ("csrr %0, %1" \ : "=r" (v) \ : "n" (csr) \ : /* clobbers: none */ ) #define CSRR_WRITE(v, csr) \ /* CSRR_WRITE(v, csr): \ * csr: MUST be a compile time integer 12-bit constant (0-4095) \ */ \ __asm__ __volatile__ ("csrw %0, %1" \ : \ : "n" (csr), "rK" (v) \ : /* clobbers: none */ ) struct pmp_entry_s { uintptr_t addr; uint8_t cfg; }; int pmp_clear(); int pmp_read_pmpcfg(unsigned int offset, uintptr_t * dest); int pmp_read_pmpaddr(unsigned int offset, uintptr_t * dest); int pmp_write_pmpcfg(unsigned int offset, uintptr_t * src); int pmp_write_pmpaddr(unsigned int offset, uintptr_t * src); int pmp_entry_read(unsigned int id, struct pmp_entry_s * entry); int pmp_entry_write(unsigned int id, struct pmp_entry_s * entry); int pmp_is_cfg_legal(unsigned int cfg); ================================================ FILE: testbench/tests/pmp/pmp.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { . = 0x80000000; _text = .; .text : { *(.text.init*) *(.text*) } _text_end = .; _end = .; . = ALIGN(4096); _data = .; .data : { *(.*data) *(.rodata*) *(.sbss) } _bss = .; .bss : { *(.bss) } _data_end = .; . = ALIGN(4096); _area = .; .area : { *(.area.bufr) *(.area.code) } . = ALIGN(4096); . = ALIGN(8192); _stack_lo = .; . += 8192; _stack_hi = .; . = 0xd0580000; .data.io . (NOLOAD) : { KEEP( *(.data.io) ) } } ================================================ FILE: testbench/tests/pmp/pmp.mki ================================================ OFILES = crt0.o main.o pmp.o veer.o fault.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/tests/pmp/trap.h ================================================ /* * SPDX-License-Identifier: BSD-3-Clause * * Copyright © 2020 Sebastian Meyer * Copyright 2023 Antmicro, Ltd. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Derived from picolibc: picocrt/machine/riscv/crt0.c */ #ifndef _TRAP_H #define _TRAP_H struct fault { unsigned long r[32]; unsigned long mepc; unsigned long mcause; unsigned long mtval; }; #endif ================================================ FILE: testbench/tests/pmp/veer.c ================================================ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2023 Antmicro, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "veer.h" #if USE_HTIF extern volatile uint64_t tohost; extern volatile uint64_t fromhost; int64_t veer_syscall (int64_t a0, int64_t a1, int64_t a2, int64_t a3) { // HTIF syscall command. It uses 8 args but for most cases 4 is enough. volatile int64_t cmd[8] = { a0, a1, a2, a3, 0, 0, 0, 0 }; // Write a pointer to the command buffer to "tohost" tohost = (uint64_t)(uintptr_t)cmd; // Wait for response in "fromhost" while (1) { volatile uint64_t fh = fromhost; if (fh != 0) { fromhost = 0; // reply break; } } return cmd[0]; } #else extern volatile char tohost; #endif __attribute__((__noreturn__)) void _exit (int status) { #if USE_HTIF veer_syscall (HTIF_SYSCALL_EXIT, status, 0, 0); #else if (!status) tohost = 0xff; else tohost = 0x01; #endif while (1); } int veer_tb_putc(char c, FILE *stream) { (void) stream; #if USE_HTIF // Do putc() via htif "bcd" device in Spike tohost = (1LL << 56) | (1LL << 48) | c; while (tohost != 0); // wait for reply #else tohost = c; #endif return c; } static FILE __stdio = FDEV_SETUP_STREAM(veer_tb_putc, NULL, NULL, _FDEV_SETUP_WRITE); FILE *const stdin = &__stdio; __strong_reference(stdin, stdout); __strong_reference(stdin, stderr); ================================================ FILE: testbench/tests/pmp/veer.h ================================================ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2023 Antmicro, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __VEER_H #define __VEER_H // Set to 1 if using HTIF interface eg. in Spike #define USE_HTIF 0 #include struct rv_jmp_buf { long pc; unsigned long regs[31]; long exitcode; }; // RISC-V specific setjmp() variant. Must be called from M-mode extern long rv_setjmp_m (struct rv_jmp_buf*); // RISC-V specific longjmp() variant. Must be called from M-mode extern void rv_longjmp_m (struct rv_jmp_buf*, long exitcode); #define TRY do { struct rv_jmp_buf try_buf = {0}; if(!rv_setjmp_m(&try_buf)) { fault_setjmp(&try_buf); #define CATCH } else { #define END_TRY } } while(0) __attribute__((__noreturn__)) void _exit (int status); #if USE_HTIF #define HTIF_SYSCALL_WRITE 64 #define HTIF_SYSCALL_EXIT 93 int64_t veer_syscall (int64_t a0, int64_t a1, int64_t a2, int64_t a3); #endif #endif ================================================ FILE: testbench/tests/pmp_random/generate_random.sh ================================================ #!/usr/bin/env bash set -e outfile=random_data.h iterations=100 printf '// This file was generated with generate_random.sh\n\n' > $outfile echo "#define RANDOM_ITERATIONS $iterations" >> $outfile echo 'const uint32_t rand_address [] = {' >> $outfile # generate random data in hex, fold each 8 hex digits, prepend '0x', append ',' tr -dc 'A-F0-9' < /dev/urandom | dd bs=1 count=$((8 * $iterations)) 2>/dev/null | \ fold -w8 | \ sed 's/^/ 0x/' | \ sed 's/$/,/' >> $outfile echo >> $outfile echo '};' >> $outfile echo 'const uint32_t rand_config [] = {' >> $outfile # generate random data in hex, fold each 8 hex digits, prepend '0x', append ',' tr -dc 'A-F0-9' < /dev/urandom | dd bs=1 count=$((8 * $iterations)) 2>/dev/null | \ fold -w8 | \ sed 's/^/ 0x/' | \ sed 's/$/,/' >> $outfile echo >> $outfile echo '};' >> $outfile ================================================ FILE: testbench/tests/pmp_random/main.c ================================================ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2025 Antmicro, Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "veer.h" #include "fault.h" #include "pmp.h" #include "random_data.h" #define mailbox_addr 0xd0580000 extern uint32_t _text; extern uint32_t _text_end; extern uint32_t _data; extern uint32_t _data_end; extern uint32_t _stack_lo; extern uint32_t _stack_hi; extern uint32_t _area; extern uint32_t tohost; // ============================================================================ const uint32_t test_pattern_a [] = { 0xE8C50A2E, 0x017F84CA, 0xFB8A3138, 0xFDF0F930, 0xA5F12034, 0x4A67B7B6, 0xD03C9377, 0xD124A11C, 0xAB319961, 0xF94AF557, 0xDD743AE6, 0xAAB99BC3, 0xE992D7FA, 0x5C6A76FA, 0xD8D63FE2, 0x8616CFC6 }; const uint32_t test_pattern_b [] = { 0x2B0B56F2, 0x6B78B6FF, 0xE7B61C7A, 0x66FB04DB, 0xC2F2BE9D, 0x2D569A89, 0x905BF8E6, 0x2798E7CE, 0x509BA997, 0xBF0147EB, 0x09065BEF, 0x04146267, 0xC421C6E3, 0xD6C76040, 0x773AA931, 0x01C01BDE }; volatile unsigned long did_execute = 0; void __attribute__((noinline)) test_hello () { did_execute = 1; printf(" hello\n"); } int __attribute__((noinline)) test_read (const uint32_t* pattern, uint32_t* source, size_t size) { did_execute = 1; printf(" reading from 0x%x...\n", source); if (memcmp(source, pattern, size)) { printf(" data mismatch\n"); return -1; } else { printf(" data match\n"); } return 0; } void __attribute__((noinline)) test_write (const uint32_t* pattern, uint32_t* target, size_t size) { did_execute = 1; printf(" writing to 0x%x...\n", target); memcpy((void*)target, pattern, size); } void __attribute__((noinline, naked, optimize("O0"), section(".area.code"))) test_exec () { asm volatile ("ret"); } // ============================================================================ volatile unsigned long trap_count = 0; int trap_handler (const struct fault* fault) { printf(" Trap! mcause=0x%08x, mepc=0x%08X, sp=0x%08X\n", fault->mcause, fault->mepc, fault->r[2]); // Terminate the simulation if too many traps got triggered if (++trap_count > 100) { printf("Too many traps, aborting...\n"); _exit(-1); } // If setjmp-based try-catch was used return to the program fault_return(fault); return 0; } // ============================================================================ // Convert byte address for PMP. Effectively does "ceil(x / 4)" #define ADDR2PMP(x) ((((uint32_t)(x)) & 3) ? ((((uint32_t)(x)) >> 2) + 1) : \ (((uint32_t)(x)) >> 2)) enum RegionType { OFF = 0, TOR = 1, NA4 = 2, NAPOT = 3 }; uint32_t reconcile_address(uint32_t address) { uint32_t area_end = ((uint32_t)&_area) + 0x40; address &= 0x7fffffff; // do not use 0xf region while (((address < (uint32_t)&_stack_hi && address >= (uint32_t)&_stack_lo) ||(address >= (uint32_t)&_text && address < (uint32_t)&_text_end) ||(address >= (uint32_t)&_data && address < (uint32_t)&_data_end) ||(address >= (uint32_t)&_area && address < area_end) ||(address >= 0x10000000 && address < 0x20000000) // csrs ||(address >= 0x00000 && address < 0x40000) // reserved ||(address >= 0x60000 && address < 0x80000) // reserved ||(address >= 0x60000 && address < 0x80000) // reserved ||(address >= 0xa0000 && address < 0x10000000) // reserved ||(address == mailbox_addr)) && (address != 0) ) { address >>= 1; } if (address == 0) { // 0 is reserved, fallback address = 0x76543210; } return address; } uint32_t legalize_address(uintptr_t address, enum RegionType region_type) { switch (region_type) { case OFF: return 0; case TOR: return 0; case NA4: // Do not use two most significant bits, VeeR ties them to 0 anyway. address &= 0x3fffffff; break; case NAPOT: // Do not use regions smaller than 32-bytes address |= 3; // Do not use large regions. if ((address & 0x3ff) == 0x3ff) address &= ~(1<<7); // Do not use two most significant bits, VeeR ties them to 0 anyway. address &= 0x3fffffff; break; default: break; } return address; } uint8_t legalize_config(uint32_t config) { uint32_t tmp_config = config; // if not enabled, shift right until it's a valid enabled region. // if it's 0, give up. while ((((config & PMP_MODE_MASK) == PMP_OFF) || ((config & PMP_MODE_MASK) == PMP_TOR)) && (tmp_config>>3) !=0) { config &= ~PMP_MODE_MASK; config |= tmp_config & PMP_MODE_MASK; tmp_config >>= 1; } // if no valid mode was found in the random data, fallback to NAPOT if (((config & PMP_MODE_MASK) == PMP_OFF) ||(config & PMP_MODE_MASK) == PMP_TOR) { config &= ~PMP_MODE_MASK; config |= PMP_NAPOT; } tmp_config = config; while ((((config & PMP_RWX_MASK) == PMP_W) || ((config & PMP_RWX_MASK) == (PMP_W | PMP_X))) & (tmp_config != 0)) { // -W- is illegal, -WX is illegal, find another config config &= ~PMP_RWX_MASK; config |= tmp_config & PMP_RWX_MASK; tmp_config >>= 1; } // This test assumes Lock is 0 config &= ~PMP_LOCK; // config registers are 8bit config &= 0xff; return (uint8_t)config; } #define TST_R 1 #define TST_W 2 #define TST_X 4 #define TST_M 16 #define trailing_ones(x) __builtin_ctz(~x & (x + 1)) uint32_t generate_napot_mask(uint32_t value) { // Find the position of the first zero uint32_t pos = trailing_ones(value); // Create a mask with 'pos' number of ones uint32_t mask = (1U << pos) - 1; return mask; } int get_effective_range(uintptr_t * const address, enum RegionType region_type, uintptr_t * const addr_hi, uintptr_t * const addr_lo) { *address = legalize_address(*address, region_type); // address is the value to be written to address register // addr_hi and addr_lo should hold actual addresses uint32_t mask = generate_napot_mask(*address); uintptr_t new_address = 0; switch (region_type) { case OFF: *addr_lo = 0; *addr_hi = 0; break; case TOR: *addr_lo = 0; *addr_hi = *address << 2; break; case NA4: *addr_lo = *address << 2; new_address = reconcile_address(*addr_lo); if (new_address != (*addr_lo)) { *addr_lo = new_address; // need to update the address to be written to register as well *address = *addr_lo >> 2; } *addr_hi = *addr_lo + 3; break; case NAPOT: *addr_lo = ((uint32_t)*address & ~mask) << 2; new_address = reconcile_address(*addr_lo); if (new_address != (*addr_lo)) { *addr_lo = new_address; // need to update the address to be written to register as well *address &= ~mask; *address |= ((new_address >> 2) & ~mask); } *addr_hi = *addr_lo + (1 << (trailing_ones(*address)+3)) - 1; break; default: break; } return 0; } int main () { printf("Hello VeeR (M mode)\n"); // ....................................................................... // Determine PMP granularity uintptr_t tmp = 0; pmp_write_pmpcfg (0, &tmp); tmp = 0xFFFFFFFF; pmp_write_pmpaddr(0, &tmp); pmp_read_pmpaddr (0, &tmp); int g = 0; for (; g < 32; ++g) { if (tmp & 1) break; tmp >>= 1; } printf("PMP G=%d, granularity is %d\n", g, 1 << (g + 2)); // ....................................................................... struct pmp_entry_s random_entry; int tid = 0; int failed = 0; pmp_clear(); // ................................ // Do the tests // This test iterates over random data (see random_data.h) // which contains values for address and configuration. // Random data needs to be adjusted to represent legal configurations. // Currently each iteration configures only one region and the others remain OFF. // TOR regions are not used. // use regions 6..15 for random data int region_for_rand_data = 6; for (int rand_test_i = 0; rand_test_i> 3) & 3; uintptr_t addr_hi = 0; uintptr_t addr_lo = 0; uint32_t region_size = 0; // Get access rights from `config`. uint32_t r = ((config & PMP_R) == PMP_R) ? 1 : 0; uint32_t w = ((config & PMP_W) == PMP_W) ? 1 : 0; uint32_t x = ((config & PMP_X) == PMP_X) ? 1 : 0; /* Calculate effective range using type and addr. */ get_effective_range(&address, region_type, &addr_hi, &addr_lo); region_size = addr_hi - addr_lo + 1; // Effective mode uint32_t r_eff = 1; // not using user mode or Lock uint32_t w_eff = 1; // not using user mode or Lock uint32_t x_eff = x; char pstr[4] = { r ? 'R' : '-', w ? 'W' : '-', x ? 'X' : '-', 0x00 }; printf("%02d - Machine mode: test %s in region(%d): 0x%x - 0x%x, size:0x%x\n", tid++, pstr, region_type, addr_lo, addr_hi, region_size); // Write data to the tested region before configuring PMP. const uint32_t* pattern = (i & 1) ? test_pattern_b : test_pattern_a; const uint32_t* other = (i & 1) ? test_pattern_a : test_pattern_b; size_t test_size = (region_size > sizeof(other)) ? sizeof(other) : region_size; memcpy((void*)addr_lo, other, test_size); // Disable the region previously used for random data. random_entry.cfg = PMP_OFF; random_entry.addr = 0; pmp_entry_write(region_for_rand_data, &random_entry); // Use the next region for random data (from the range 6..15) region_for_rand_data = (region_for_rand_data < 15) ? region_for_rand_data+1 : 6; random_entry.cfg = config; random_entry.addr = address; pmp_entry_write(region_for_rand_data, &random_entry); // Check struct pmp_entry_s readback; pmp_entry_read(region_for_rand_data, &readback); // An illegal PMP region configuration has been written and readback // this is an error // // -W- and -WX combinations are reserved except for when Smepmp is // present and mseccfg.MML=1. This test does not enable the latter // so the combinations are not legal. if (!pmp_is_cfg_legal(readback.cfg)) { printf(" error, an illegal PMP configuration accepted by the core\n", readback.cfg); failed++; continue; } int exc; int cmp; int any_fail = 0; // Test writing. Write pattern from user mode and check if it was // successfully written. printf(" testing W...\n"); did_execute = 0; exc = 0; TRY { test_write(pattern, (uint32_t *)addr_lo, test_size); } CATCH { exc = 1; } END_TRY; cmp = memcmp((void*)addr_lo, pattern, test_size); if (cmp) { printf(" data mismatch\n"); } else { printf(" data match\n"); } if (did_execute && ((!w_eff && exc && cmp) || (w_eff && !exc && !cmp))) { printf(" pass\n"); } else { printf(" fail\n"); any_fail = 1; } // Test reading. Read area from user mode and compare against the // pattern printf(" testing R...\n"); // Write pattern if (!w_eff) { memcpy((void*)addr_lo, pattern, test_size); } did_execute = 0; exc = 0; TRY { cmp = test_read(pattern, (uint32_t *)addr_lo, test_size); } CATCH { exc = 1; } END_TRY; if (did_execute && ((!r_eff && exc) || (r_eff && !exc && !cmp))) { printf(" pass\n"); } else { printf(" fail\n"); any_fail = 1; } #ifdef TEST_X // TODO test execution rights void (*copied_test_exec)(); random_entry.cfg = PMP_OFF; pmp_entry_write(region_for_rand_data, &random_entry); // Copy `test_exec` into the region // test_exec contains only 'ret' and any region is at least 4 bytes in size memcpy((void*)addr_lo, &test_exec, 4); random_entry.cfg = config; pmp_entry_write(region_for_rand_data, &random_entry); copied_test_exec = (void(*)())addr_lo; // Call a function placed in the designated area printf(" testing X...\n"); TRY { copied_test_exec(); if (x_eff) { printf(" pass\n"); } else { printf(" fail\n"); any_fail = 1; } } CATCH { if (x_eff) { printf(" fail\n"); any_fail = 1; } else { printf(" pass\n"); } } END_TRY; #endif // TEST_X if (any_fail) printf(" random data used:\n addr: 0x%x,\n cfg: 0x%x\n", rand_address[rand_test_i], rand_config[rand_test_i]); // Count fails failed += any_fail; } // ....................................................................... printf(" %d/%d passed\n", tid - failed, tid); int res = (failed == 0) ? 0 : -1; if (!res) printf("*** PASSED ***\n"); else printf("*** FAILED ***\n"); printf("Goodbye VeeR (M mode)\n"); _exit(res); return res; } ================================================ FILE: testbench/tests/pmp_random/pmp_random.mki ================================================ OFILES = crt0.o main.o pmp.o veer.o fault.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/tests/pmp_random/random_data.h ================================================ // This file was generated with generate_random.sh #define RANDOM_ITERATIONS 100 const uint32_t rand_address [] = { 0x0B83C7A8, 0x932F8872, 0x706A93B6, 0x70CB16E2, 0x4C44A3AC, 0x2A59C3F9, 0x25E88A72, 0x59E5C411, 0x337EF084, 0xA4468545, 0xEC472E58, 0x62186731, 0xABBBC86F, 0xF47EF033, 0x455B1035, 0x8EC8CAC1, 0x735DB130, 0x59A9DEE0, 0x836F7C3D, 0x1548C4E8, 0xE54DF150, 0x0352C401, 0x94E97F84, 0x3E39566D, 0x160BEFAE, 0x96872866, 0x2042BFA2, 0x66899B2A, 0x8EE30A51, 0x382ACF88, 0x45E5CBB8, 0xB7DA90F4, 0x2B7EAC8B, 0x72EB2667, 0x3A8F29E9, 0xFFE2EB46, 0x8F1938F4, 0x0B20F017, 0x48FB3EE6, 0x8F13D256, 0x9010A66A, 0x9EAAB8FE, 0x8172F809, 0x679D4C64, 0xA72CB05B, 0x6F37C8C0, 0xC5EF0789, 0x21ADC433, 0x14F798D9, 0xEABFC6CC, 0x4D125944, 0x0E7B7BF2, 0x65054B8D, 0x357F8EE9, 0x536E0B7A, 0xF42E6D48, 0x3B5A273B, 0x13A45B43, 0xFF2F7EC9, 0x8314E3FF, 0x6C7C5F2F, 0x95C0DADD, 0x94C6E8BD, 0x6ACCB9A6, 0x50E25BF3, 0x0C16BDAE, 0xE87B24FB, 0x60998517, 0xA29CB152, 0xED404EE7, 0x26389409, 0x7CFE1BC9, 0xB345E605, 0x6BEA3E3C, 0xB440CC05, 0xFD53FE05, 0xDF905CA7, 0xE8A5F3C4, 0x7BE1511F, 0x18937217, 0xA9301272, 0x4A820E35, 0xF9ABCD6C, 0x37C7DD03, 0x5FB938C7, 0xE208800E, 0xD5D9A331, 0xB8431823, 0x870E5AC9, 0x269EE21B, 0x6B04E971, 0x06225C28, 0x10AA81F0, 0x35A5705B, 0xFED7C35D, 0x8E1662BC, 0xC3A465BC, 0x33D21CEC, 0xD9B6A900, 0x2C52B111, }; const uint32_t rand_config [] = { 0xDCB82A76, 0xAC807B43, 0x69565CFC, 0x1A1BAD9A, 0x489B02B1, 0xF816E1A5, 0xA9A09ECD, 0x5B1665D6, 0xBFFB4CD6, 0x38B55DF1, 0x25D726FF, 0x5C10A678, 0x4F906A7C, 0xA389B951, 0xB0A9BED9, 0x168DE1E7, 0x6CAF04D2, 0x38BEE72E, 0x66C17FDB, 0x91DBA709, 0xC67F07D5, 0xB7F1294C, 0xE64F7874, 0x905BE8F4, 0x0B5F8D27, 0x77C09D20, 0x00764B23, 0x69BEAF8C, 0xDA9ABA16, 0x4717E8A7, 0x56FBDFD2, 0x267AF0D3, 0x3BBDB755, 0xE2E93169, 0xD2908EF7, 0x90B41356, 0x7D99B034, 0x25B56A53, 0x95E2C49F, 0x0C744355, 0xB013AE0A, 0x7AB0770A, 0x32E23805, 0x08229CC3, 0x2A15888A, 0x2F832722, 0x1E8C1189, 0x95119BCD, 0x05FA1928, 0x8E47DEAE, 0xE4C912B1, 0xD06BBE96, 0x4720C888, 0xFE1921DE, 0x78C857E4, 0x850B6219, 0xB8CDEEA5, 0xD957D370, 0xEF543FAE, 0x61DA6905, 0xB1954F69, 0xB21BC2DA, 0x1A135E21, 0x9A335436, 0x92A1555F, 0xEAAE8153, 0x48375B22, 0x418D23EA, 0x8D9B518F, 0x91EE2305, 0x6C5874EA, 0x908D875B, 0xB0E38A8F, 0x7B605FFD, 0xDDD51177, 0x7546C6C6, 0x45907EC7, 0x5DF27880, 0x304AF3FB, 0x190AE837, 0x7B6EF9DD, 0x98EEDFBC, 0x5639192B, 0xC008C201, 0xF291065C, 0xFAA092FA, 0x92C2BCEA, 0x93D8F8FC, 0xFC980FDD, 0x98D97B3F, 0x9C37EACB, 0xD99ABF8B, 0x81B3B931, 0xF9CA2C36, 0x3424181B, 0x98A4BF18, 0x2FD986FA, 0x379C629D, 0x0D1221E5, 0x7E3D572F, }; ================================================ FILE: testbench/tests/write_unaligned/crt0.s ================================================ # SPDX-License-Identifier: Apache-2.0 .section .text.init .global _start _start: # Setup stack la sp, STACK # Call main() call main # Map exit code: == 0 - success, != 0 - failure mv a1, a0 li a0, 0xff # ok beq a1, x0, _finish li a0, 1 # fail .global _finish _finish: la t0, tohost sb a0, 0(t0) # Signal testbench termination beq x0, x0, _finish .rept 10 nop .endr .section .data.io .global tohost tohost: .word 0 ================================================ FILE: testbench/tests/write_unaligned/write_unaligned.c ================================================ #include int handler() __attribute__((section(".handler"))); int handler() { return 0; } int main () { int (*func)() = (int (*)())0x70000001; volatile uint32_t csr_value; printf("jumping to 0x70000001\n"); func(); printf("jumping to 0x80001\n"); func = 0x80001; func(); printf("jumping to 0xe000001\n"); func = 0xe000001; func(); printf("jumping to 0x3fffffff\n"); func = 0x3fffffff; func(); printf("jumping to 0xa001\n"); func = 0xa001; func(); // read CSR at address 0x7FF (mscause) __asm__ volatile ("csrr %0, 0x7FF" : "=r"(csr_value)); return 0; } ================================================ FILE: testbench/tests/write_unaligned/write_unaligned.ld ================================================ /* SPDX-License-Identifier: Apache-2.0 */ OUTPUT_ARCH( "riscv" ) ENTRY(_start) SECTIONS { .handler : { KEEP(*(.handler)) } > RAM = 0x0 . = 0x80000000; .text : { *(.text.init*) *(.text*) } _end = .; .data : { *(.*data) *(.rodata*) *(.sbss) STACK = ALIGN(16) + 0x1000;} .bss : { *(.bss) } . = 0xd0580000; .data.io . : { *(.data.io) } } ================================================ FILE: testbench/tests/write_unaligned/write_unaligned.mki ================================================ # SPDX-License-Identifier: Apache-2.0 OFILES = crt0.o write_unaligned.o printf.o TEST_CFLAGS = -g -O3 -falign-functions=16 ================================================ FILE: testbench/user_cells.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // This file contains examples of user (technology specific) cells that can // be used thruought the core // Clock gate example module user_clock_gate ( input logic CK, output logic Q, input logic EN ); logic gate; initial gate = 0; always @(negedge CK) gate <= EN; assign Q = CK & gate; endmodule ================================================ FILE: testbench/veer_wrapper.sv ================================================ //******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2023 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //******************************************************************************** module veer_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic dbg_rst_l, input logic [31:1] rst_vec, input logic nmi_int, input logic [31:1] nmi_vec, input logic [31:1] jtag_id, output logic [31:0] trace_rv_i_insn_ip, output logic [31:0] trace_rv_i_address_ip, output logic trace_rv_i_valid_ip, output logic trace_rv_i_exception_ip, output logic [ 4:0] trace_rv_i_ecause_ip, output logic trace_rv_i_interrupt_ip, output logic [31:0] trace_rv_i_tval_ip, // Bus signals `ifdef RV_BUILD_AXI4 //-------------------------- LSU AXI signals-------------------------- // AXI Write Channels output logic lsu_axi_awvalid, input logic lsu_axi_awready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid, output logic [ 31:0] lsu_axi_awaddr, output logic [ 3:0] lsu_axi_awregion, output logic [ 7:0] lsu_axi_awlen, output logic [ 2:0] lsu_axi_awsize, output logic [ 1:0] lsu_axi_awburst, output logic lsu_axi_awlock, output logic [ 3:0] lsu_axi_awcache, output logic [ 2:0] lsu_axi_awprot, output logic [ 3:0] lsu_axi_awqos, output logic lsu_axi_wvalid, input logic lsu_axi_wready, output logic [63:0] lsu_axi_wdata, output logic [ 7:0] lsu_axi_wstrb, output logic lsu_axi_wlast, input logic lsu_axi_bvalid, output logic lsu_axi_bready, input logic [ 1:0] lsu_axi_bresp, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid, // AXI Read Channels output logic lsu_axi_arvalid, input logic lsu_axi_arready, output logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid, output logic [ 31:0] lsu_axi_araddr, output logic [ 3:0] lsu_axi_arregion, output logic [ 7:0] lsu_axi_arlen, output logic [ 2:0] lsu_axi_arsize, output logic [ 1:0] lsu_axi_arburst, output logic lsu_axi_arlock, output logic [ 3:0] lsu_axi_arcache, output logic [ 2:0] lsu_axi_arprot, output logic [ 3:0] lsu_axi_arqos, input logic lsu_axi_rvalid, output logic lsu_axi_rready, input logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid, input logic [ 63:0] lsu_axi_rdata, input logic [ 1:0] lsu_axi_rresp, input logic lsu_axi_rlast, //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels output logic ifu_axi_awvalid, input logic ifu_axi_awready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid, output logic [ 31:0] ifu_axi_awaddr, output logic [ 3:0] ifu_axi_awregion, output logic [ 7:0] ifu_axi_awlen, output logic [ 2:0] ifu_axi_awsize, output logic [ 1:0] ifu_axi_awburst, output logic ifu_axi_awlock, output logic [ 3:0] ifu_axi_awcache, output logic [ 2:0] ifu_axi_awprot, output logic [ 3:0] ifu_axi_awqos, output logic ifu_axi_wvalid, input logic ifu_axi_wready, output logic [63:0] ifu_axi_wdata, output logic [ 7:0] ifu_axi_wstrb, output logic ifu_axi_wlast, input logic ifu_axi_bvalid, output logic ifu_axi_bready, input logic [ 1:0] ifu_axi_bresp, input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_bid, // AXI Read Channels output logic ifu_axi_arvalid, input logic ifu_axi_arready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid, output logic [ 31:0] ifu_axi_araddr, output logic [ 3:0] ifu_axi_arregion, output logic [ 7:0] ifu_axi_arlen, output logic [ 2:0] ifu_axi_arsize, output logic [ 1:0] ifu_axi_arburst, output logic ifu_axi_arlock, output logic [ 3:0] ifu_axi_arcache, output logic [ 2:0] ifu_axi_arprot, output logic [ 3:0] ifu_axi_arqos, input logic ifu_axi_rvalid, output logic ifu_axi_rready, input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid, input logic [ 63:0] ifu_axi_rdata, input logic [ 1:0] ifu_axi_rresp, input logic ifu_axi_rlast, //-------------------------- SB AXI signals-------------------------- // AXI Write Channels output logic sb_axi_awvalid, input logic sb_axi_awready, output logic [pt.SB_BUS_TAG-1:0] sb_axi_awid, output logic [ 31:0] sb_axi_awaddr, output logic [ 3:0] sb_axi_awregion, output logic [ 7:0] sb_axi_awlen, output logic [ 2:0] sb_axi_awsize, output logic [ 1:0] sb_axi_awburst, output logic sb_axi_awlock, output logic [ 3:0] sb_axi_awcache, output logic [ 2:0] sb_axi_awprot, output logic [ 3:0] sb_axi_awqos, output logic sb_axi_wvalid, input logic sb_axi_wready, output logic [63:0] sb_axi_wdata, output logic [ 7:0] sb_axi_wstrb, output logic sb_axi_wlast, input logic sb_axi_bvalid, output logic sb_axi_bready, input logic [ 1:0] sb_axi_bresp, input logic [pt.SB_BUS_TAG-1:0] sb_axi_bid, // AXI Read Channels output logic sb_axi_arvalid, input logic sb_axi_arready, output logic [pt.SB_BUS_TAG-1:0] sb_axi_arid, output logic [ 31:0] sb_axi_araddr, output logic [ 3:0] sb_axi_arregion, output logic [ 7:0] sb_axi_arlen, output logic [ 2:0] sb_axi_arsize, output logic [ 1:0] sb_axi_arburst, output logic sb_axi_arlock, output logic [ 3:0] sb_axi_arcache, output logic [ 2:0] sb_axi_arprot, output logic [ 3:0] sb_axi_arqos, input logic sb_axi_rvalid, output logic sb_axi_rready, input logic [pt.SB_BUS_TAG-1:0] sb_axi_rid, input logic [ 63:0] sb_axi_rdata, input logic [ 1:0] sb_axi_rresp, input logic sb_axi_rlast, //-------------------------- DMA AXI signals-------------------------- // AXI Write Channels input logic dma_axi_awvalid, output logic dma_axi_awready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid, input logic [ 31:0] dma_axi_awaddr, input logic [ 2:0] dma_axi_awsize, input logic [ 2:0] dma_axi_awprot, input logic [ 7:0] dma_axi_awlen, input logic [ 1:0] dma_axi_awburst, input logic dma_axi_wvalid, output logic dma_axi_wready, input logic [63:0] dma_axi_wdata, input logic [ 7:0] dma_axi_wstrb, input logic dma_axi_wlast, output logic dma_axi_bvalid, input logic dma_axi_bready, output logic [ 1:0] dma_axi_bresp, output logic [pt.DMA_BUS_TAG-1:0] dma_axi_bid, // AXI Read Channels input logic dma_axi_arvalid, output logic dma_axi_arready, input logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid, input logic [ 31:0] dma_axi_araddr, input logic [ 2:0] dma_axi_arsize, input logic [ 2:0] dma_axi_arprot, input logic [ 7:0] dma_axi_arlen, input logic [ 1:0] dma_axi_arburst, output logic dma_axi_rvalid, input logic dma_axi_rready, output logic [pt.DMA_BUS_TAG-1:0] dma_axi_rid, output logic [ 63:0] dma_axi_rdata, output logic [ 1:0] dma_axi_rresp, output logic dma_axi_rlast, `endif `ifdef RV_BUILD_AHB_LITE //// AHB LITE BUS output logic [31:0] haddr, output logic [ 2:0] hburst, output logic hmastlock, output logic [ 3:0] hprot, output logic [ 2:0] hsize, output logic [ 1:0] htrans, output logic hwrite, input logic [63:0] hrdata, input logic hready, input logic hresp, // LSU AHB Master output logic [31:0] lsu_haddr, output logic [ 2:0] lsu_hburst, output logic lsu_hmastlock, output logic [ 3:0] lsu_hprot, output logic [ 2:0] lsu_hsize, output logic [ 1:0] lsu_htrans, output logic lsu_hwrite, output logic [63:0] lsu_hwdata, input logic [63:0] lsu_hrdata, input logic lsu_hready, input logic lsu_hresp, // Debug Syster Bus AHB output logic [31:0] sb_haddr, output logic [ 2:0] sb_hburst, output logic sb_hmastlock, output logic [ 3:0] sb_hprot, output logic [ 2:0] sb_hsize, output logic [ 1:0] sb_htrans, output logic sb_hwrite, output logic [63:0] sb_hwdata, input logic [63:0] sb_hrdata, input logic sb_hready, input logic sb_hresp, // DMA Slave input logic dma_hsel, input logic [31:0] dma_haddr, input logic [ 2:0] dma_hburst, input logic dma_hmastlock, input logic [ 3:0] dma_hprot, input logic [ 2:0] dma_hsize, input logic [ 1:0] dma_htrans, input logic dma_hwrite, input logic [63:0] dma_hwdata, input logic dma_hreadyin, output logic [63:0] dma_hrdata, output logic dma_hreadyout, output logic dma_hresp, `endif // clk ratio signals input logic lsu_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface input logic ifu_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface input logic dbg_bus_clk_en, // Clock ratio b/w cpu core clk & AHB master interface input logic dma_bus_clk_en, // Clock ratio b/w cpu core clk & AHB slave interface input logic timer_int, input logic soft_int, input logic [pt.PIC_TOTAL_INT:1] extintsrc_req, output logic dec_tlu_perfcnt0, // toggles when slot0 perf counter 0 has an event inc output logic dec_tlu_perfcnt1, output logic dec_tlu_perfcnt2, output logic dec_tlu_perfcnt3, // ports added by the soc team input logic jtag_tck, // JTAG clk input logic jtag_tms, // JTAG TMS input logic jtag_tdi, // JTAG tdi input logic jtag_trst_n, // JTAG Reset output logic jtag_tdo, // JTAG TDO output logic jtag_tdoEn, // JTAG Test Data Output enable input logic [31:4] core_id, // Memory Export Interface output logic mem_clk, // ICCM output logic [pt.ICCM_NUM_BANKS-1:0] iccm_clken, output logic [pt.ICCM_NUM_BANKS-1:0] iccm_wren_bank, output logic [pt.ICCM_NUM_BANKS-1:0][pt.ICCM_BITS-1:pt.ICCM_BANK_INDEX_LO] iccm_addr_bank, output logic [pt.ICCM_NUM_BANKS-1:0][31:0] iccm_bank_wr_data, output logic [pt.ICCM_NUM_BANKS-1:0][pt.ICCM_ECC_WIDTH-1:0] iccm_bank_wr_ecc, input logic [pt.ICCM_NUM_BANKS-1:0][31:0] iccm_bank_dout, input logic [pt.ICCM_NUM_BANKS-1:0][pt.ICCM_ECC_WIDTH-1:0] iccm_bank_ecc, // DCCM output logic [pt.DCCM_NUM_BANKS-1:0] dccm_clken, output logic [pt.DCCM_NUM_BANKS-1:0] dccm_wren_bank, output logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_BITS-1:(pt.DCCM_BANK_BITS+2)] dccm_addr_bank, output logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_DATA_WIDTH-1:0] dccm_wr_data_bank, output logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_FDATA_WIDTH-pt.DCCM_DATA_WIDTH-1:0] dccm_wr_ecc_bank, input logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_DATA_WIDTH-1:0] dccm_bank_dout, input logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_FDATA_WIDTH-pt.DCCM_DATA_WIDTH-1:0] dccm_bank_ecc, // ICache Export Interface // ICache Data output logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_WAYS-1:0] ic_b_sb_wren, output logic [pt.ICACHE_BANKS_WAY-1:0][(71*pt.ICACHE_NUM_WAYS)-1:0] ic_b_sb_bit_en_vec, output logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_sb_wr_data, output logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_INDEX_HI : pt.ICACHE_DATA_INDEX_LO] ic_rw_addr_bank_q, output logic [pt.ICACHE_BANKS_WAY-1:0] ic_bank_way_clken_final, output logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_bank_way_clken_final_up, input logic [pt.ICACHE_BANKS_WAY-1:0][(71*pt.ICACHE_NUM_WAYS)-1:0] wb_packeddout_pre, input logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][71-1:0] wb_dout_pre_up, // ICache Tag output logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_clken_final, output logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_wren_q, output logic [(26*pt.ICACHE_NUM_WAYS)-1 :0] ic_tag_wren_biten_vec, output logic [25:0] ic_tag_wr_data, output logic [pt.ICACHE_INDEX_HI: pt.ICACHE_TAG_INDEX_LO] ic_rw_addr_q, input logic [pt.ICACHE_NUM_WAYS-1:0] [25:0] ic_tag_data_raw_pre, input logic [(26*pt.ICACHE_NUM_WAYS)-1 :0] ic_tag_data_raw_packed_pre, // ICCM/DCCM ECC status output logic iccm_ecc_single_error, output logic iccm_ecc_double_error, output logic dccm_ecc_single_error, output logic dccm_ecc_double_error, `ifdef RV_LOCKSTEP_ENABLE input logic disable_corruption_detection_i, input logic lockstep_err_injection_en_i, output logic corruption_detected_o, `endif // external MPC halt/run interface input logic mpc_debug_halt_req, // Async halt request input logic mpc_debug_run_req, // Async run request input logic mpc_reset_run_req, // Run/halt after reset output logic mpc_debug_halt_ack, // Halt ack output logic mpc_debug_run_ack, // Run ack output logic debug_brkpt_status, // debug breakpoint input logic i_cpu_halt_req, // Async halt req to CPU output logic o_cpu_halt_ack, // core response to halt output logic o_cpu_halt_status, // 1'b1 indicates core is halted output logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request input logic i_cpu_run_req, // Async restart req to CPU output logic o_cpu_run_ack, // Core response to run req input logic scan_mode, // To enable scan mode input logic mbist_mode, // to enable mbist input logic dmi_core_enable, // DMI port for uncore input logic dmi_uncore_enable, output logic dmi_uncore_en, output logic dmi_uncore_wr_en, output logic [ 6:0] dmi_uncore_addr, output logic [31:0] dmi_uncore_wdata, input logic [31:0] dmi_uncore_rdata, output logic dmi_active ); el2_mem_if mem_export (); assign mem_clk = mem_export.clk; assign dccm_clken = mem_export.dccm_clken; assign dccm_wren_bank = mem_export.dccm_wren_bank; assign dccm_addr_bank = mem_export.dccm_addr_bank; assign dccm_wr_data_bank = mem_export.dccm_wr_data_bank; assign dccm_wr_ecc_bank = mem_export.dccm_wr_ecc_bank; assign mem_export.dccm_bank_dout = dccm_bank_dout; assign mem_export.dccm_bank_ecc = dccm_bank_ecc; assign iccm_clken = mem_export.iccm_clken; assign iccm_wren_bank = mem_export.iccm_wren_bank; assign iccm_addr_bank = mem_export.iccm_addr_bank; assign iccm_bank_wr_data = mem_export.iccm_bank_wr_data; assign iccm_bank_wr_ecc = mem_export.iccm_bank_wr_ecc; assign mem_export.iccm_bank_dout = iccm_bank_dout; assign mem_export.iccm_bank_ecc = iccm_bank_ecc; // ICache Data assign ic_b_sb_wren = mem_export.ic_b_sb_wren; assign ic_b_sb_bit_en_vec = mem_export.ic_b_sb_bit_en_vec; assign ic_sb_wr_data = mem_export.ic_sb_wr_data; assign ic_rw_addr_bank_q = mem_export.ic_rw_addr_bank_q; assign ic_bank_way_clken_final = mem_export.ic_bank_way_clken_final; assign ic_bank_way_clken_final_up = mem_export.ic_bank_way_clken_final_up; assign mem_export.wb_packeddout_pre = wb_packeddout_pre; assign mem_export.wb_dout_pre_up = wb_dout_pre_up; // ICache Data assign ic_tag_clken_final = mem_export.ic_tag_clken_final; assign ic_tag_wren_q = mem_export.ic_tag_wren_q; assign ic_tag_wren_biten_vec = mem_export.ic_tag_wren_biten_vec; assign ic_tag_wr_data = mem_export.ic_tag_wr_data; assign ic_rw_addr_q = mem_export.ic_rw_addr_q; assign mem_export.ic_tag_data_raw_packed_pre = ic_tag_data_raw_packed_pre; assign mem_export.ic_tag_data_raw_pre = ic_tag_data_raw_pre; el2_veer_wrapper rvtop ( .el2_mem_export(mem_export.veer_sram_src), .el2_icache_export(mem_export.veer_icache_src), .dmi_core_enable(dmi_core_enable), .dmi_active(dmi_active), .* ); endmodule ================================================ FILE: tools/JSON.pm ================================================ package JSON; use strict; use Carp (); use base qw(Exporter); @JSON::EXPORT = qw(from_json to_json jsonToObj objToJson encode_json decode_json); BEGIN { $JSON::VERSION = '2.53'; $JSON::DEBUG = 0 unless (defined $JSON::DEBUG); $JSON::DEBUG = $ENV{ PERL_JSON_DEBUG } if exists $ENV{ PERL_JSON_DEBUG }; } my $Module_XS = 'JSON::XS'; my $Module_PP = 'JSON::PP'; my $Module_bp = 'JSON::backportPP'; # included in JSON distribution my $PP_Version = '2.27200'; my $XS_Version = '2.27'; # XS and PP common methods my @PublicMethods = qw/ ascii latin1 utf8 pretty indent space_before space_after relaxed canonical allow_nonref allow_blessed convert_blessed filter_json_object filter_json_single_key_object shrink max_depth max_size encode decode decode_prefix allow_unknown /; my @Properties = qw/ ascii latin1 utf8 indent space_before space_after relaxed canonical allow_nonref allow_blessed convert_blessed shrink max_depth max_size allow_unknown /; my @XSOnlyMethods = qw//; # Currently nothing my @PPOnlyMethods = qw/ indent_length sort_by allow_singlequote allow_bignum loose allow_barekey escape_slash as_nonblessed /; # JSON::PP specific # used in _load_xs and _load_pp ($INSTALL_ONLY is not used currently) my $_INSTALL_DONT_DIE = 1; # When _load_xs fails to load XS, don't die. my $_INSTALL_ONLY = 2; # Don't call _set_methods() my $_ALLOW_UNSUPPORTED = 0; my $_UNIV_CONV_BLESSED = 0; my $_USSING_bpPP = 0; # Check the environment variable to decide worker module. unless ($JSON::Backend) { $JSON::DEBUG and Carp::carp("Check used worker module..."); my $backend = exists $ENV{PERL_JSON_BACKEND} ? $ENV{PERL_JSON_BACKEND} : 1; if ($backend eq '1' or $backend =~ /JSON::XS\s*,\s*JSON::PP/) { _load_xs($_INSTALL_DONT_DIE) or _load_pp(); } elsif ($backend eq '0' or $backend eq 'JSON::PP') { _load_pp(); } elsif ($backend eq '2' or $backend eq 'JSON::XS') { _load_xs(); } elsif ($backend eq 'JSON::backportPP') { $_USSING_bpPP = 1; _load_pp(); } else { Carp::croak "The value of environmental variable 'PERL_JSON_BACKEND' is invalid."; } } sub import { my $pkg = shift; my @what_to_export; my $no_export; for my $tag (@_) { if ($tag eq '-support_by_pp') { if (!$_ALLOW_UNSUPPORTED++) { JSON::Backend::XS ->support_by_pp(@PPOnlyMethods) if ($JSON::Backend eq $Module_XS); } next; } elsif ($tag eq '-no_export') { $no_export++, next; } elsif ( $tag eq '-convert_blessed_universally' ) { eval q| require B; *UNIVERSAL::TO_JSON = sub { my $b_obj = B::svref_2object( $_[0] ); return $b_obj->isa('B::HV') ? { %{ $_[0] } } : $b_obj->isa('B::AV') ? [ @{ $_[0] } ] : undef ; } | if ( !$_UNIV_CONV_BLESSED++ ); next; } push @what_to_export, $tag; } return if ($no_export); __PACKAGE__->export_to_level(1, $pkg, @what_to_export); } # OBSOLETED sub jsonToObj { my $alternative = 'from_json'; if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) { shift @_; $alternative = 'decode'; } Carp::carp "'jsonToObj' will be obsoleted. Please use '$alternative' instead."; return JSON::from_json(@_); }; sub objToJson { my $alternative = 'to_json'; if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) { shift @_; $alternative = 'encode'; } Carp::carp "'objToJson' will be obsoleted. Please use '$alternative' instead."; JSON::to_json(@_); }; # INTERFACES sub to_json ($@) { if ( ref($_[0]) eq 'JSON' or (@_ > 2 and $_[0] eq 'JSON') ) { Carp::croak "to_json should not be called as a method."; } my $json = new JSON; if (@_ == 2 and ref $_[1] eq 'HASH') { my $opt = $_[1]; for my $method (keys %$opt) { $json->$method( $opt->{$method} ); } } $json->encode($_[0]); } sub from_json ($@) { if ( ref($_[0]) eq 'JSON' or $_[0] eq 'JSON' ) { Carp::croak "from_json should not be called as a method."; } my $json = new JSON; if (@_ == 2 and ref $_[1] eq 'HASH') { my $opt = $_[1]; for my $method (keys %$opt) { $json->$method( $opt->{$method} ); } } return $json->decode( $_[0] ); } sub true { $JSON::true } sub false { $JSON::false } sub null { undef; } sub require_xs_version { $XS_Version; } sub backend { my $proto = shift; $JSON::Backend; } #*module = *backend; sub is_xs { return $_[0]->module eq $Module_XS; } sub is_pp { return not $_[0]->xs; } sub pureperl_only_methods { @PPOnlyMethods; } sub property { my ($self, $name, $value) = @_; if (@_ == 1) { my %props; for $name (@Properties) { my $method = 'get_' . $name; if ($name eq 'max_size') { my $value = $self->$method(); $props{$name} = $value == 1 ? 0 : $value; next; } $props{$name} = $self->$method(); } return \%props; } elsif (@_ > 3) { Carp::croak('property() can take only the option within 2 arguments.'); } elsif (@_ == 2) { if ( my $method = $self->can('get_' . $name) ) { if ($name eq 'max_size') { my $value = $self->$method(); return $value == 1 ? 0 : $value; } $self->$method(); } } else { $self->$name($value); } } # INTERNAL sub _load_xs { my $opt = shift; $JSON::DEBUG and Carp::carp "Load $Module_XS."; # if called after install module, overload is disable.... why? JSON::Boolean::_overrride_overload($Module_XS); JSON::Boolean::_overrride_overload($Module_PP); eval qq| use $Module_XS $XS_Version (); |; if ($@) { if (defined $opt and $opt & $_INSTALL_DONT_DIE) { $JSON::DEBUG and Carp::carp "Can't load $Module_XS...($@)"; return 0; } Carp::croak $@; } unless (defined $opt and $opt & $_INSTALL_ONLY) { _set_module( $JSON::Backend = $Module_XS ); my $data = join("", ); # this code is from Jcode 2.xx. close(DATA); eval $data; JSON::Backend::XS->init; } return 1; }; sub _load_pp { my $opt = shift; my $backend = $_USSING_bpPP ? $Module_bp : $Module_PP; $JSON::DEBUG and Carp::carp "Load $backend."; # if called after install module, overload is disable.... why? JSON::Boolean::_overrride_overload($Module_XS); JSON::Boolean::_overrride_overload($backend); if ( $_USSING_bpPP ) { eval qq| require $backend |; } else { eval qq| use $backend $PP_Version () |; } if ($@) { if ( $backend eq $Module_PP ) { $JSON::DEBUG and Carp::carp "Can't load $Module_PP ($@), so try to load $Module_bp"; $_USSING_bpPP++; $backend = $Module_bp; JSON::Boolean::_overrride_overload($backend); local $^W; # if PP installed but invalid version, backportPP redifines methods. eval qq| require $Module_bp |; } Carp::croak $@ if $@; } unless (defined $opt and $opt & $_INSTALL_ONLY) { _set_module( $JSON::Backend = $Module_PP ); # even if backportPP, set $Backend with 'JSON::PP' JSON::Backend::PP->init; } }; sub _set_module { return if defined $JSON::true; my $module = shift; local $^W; no strict qw(refs); $JSON::true = ${"$module\::true"}; $JSON::false = ${"$module\::false"}; push @JSON::ISA, $module; push @{"$module\::Boolean::ISA"}, qw(JSON::Boolean); *{"JSON::is_bool"} = \&{"$module\::is_bool"}; for my $method ($module eq $Module_XS ? @PPOnlyMethods : @XSOnlyMethods) { *{"JSON::$method"} = sub { Carp::carp("$method is not supported in $module."); $_[0]; }; } return 1; } # # JSON Boolean # package JSON::Boolean; my %Installed; sub _overrride_overload { return if ($Installed{ $_[0] }++); my $boolean = $_[0] . '::Boolean'; eval sprintf(q| package %s; use overload ( '""' => sub { ${$_[0]} == 1 ? 'true' : 'false' }, 'eq' => sub { my ($obj, $op) = ref ($_[0]) ? ($_[0], $_[1]) : ($_[1], $_[0]); if ($op eq 'true' or $op eq 'false') { return "$obj" eq 'true' ? 'true' eq $op : 'false' eq $op; } else { return $obj ? 1 == $op : 0 == $op; } }, ); |, $boolean); if ($@) { Carp::croak $@; } return 1; } # # Helper classes for Backend Module (PP) # package JSON::Backend::PP; sub init { local $^W; no strict qw(refs); # this routine may be called after JSON::Backend::XS init was called. *{"JSON::decode_json"} = \&{"JSON::PP::decode_json"}; *{"JSON::encode_json"} = \&{"JSON::PP::encode_json"}; *{"JSON::PP::is_xs"} = sub { 0 }; *{"JSON::PP::is_pp"} = sub { 1 }; return 1; } # # To save memory, the below lines are read only when XS backend is used. # package JSON; 1; __DATA__ # # Helper classes for Backend Module (XS) # package JSON::Backend::XS; use constant INDENT_LENGTH_FLAG => 15 << 12; use constant UNSUPPORTED_ENCODE_FLAG => { ESCAPE_SLASH => 0x00000010, ALLOW_BIGNUM => 0x00000020, AS_NONBLESSED => 0x00000040, EXPANDED => 0x10000000, # for developer's }; use constant UNSUPPORTED_DECODE_FLAG => { LOOSE => 0x00000001, ALLOW_BIGNUM => 0x00000002, ALLOW_BAREKEY => 0x00000004, ALLOW_SINGLEQUOTE => 0x00000008, EXPANDED => 0x20000000, # for developer's }; sub init { local $^W; no strict qw(refs); *{"JSON::decode_json"} = \&{"JSON::XS::decode_json"}; *{"JSON::encode_json"} = \&{"JSON::XS::encode_json"}; *{"JSON::XS::is_xs"} = sub { 1 }; *{"JSON::XS::is_pp"} = sub { 0 }; return 1; } sub support_by_pp { my ($class, @methods) = @_; local $^W; no strict qw(refs); my $JSON_XS_encode_orignal = \&JSON::XS::encode; my $JSON_XS_decode_orignal = \&JSON::XS::decode; my $JSON_XS_incr_parse_orignal = \&JSON::XS::incr_parse; *JSON::XS::decode = \&JSON::Backend::XS::Supportable::_decode; *JSON::XS::encode = \&JSON::Backend::XS::Supportable::_encode; *JSON::XS::incr_parse = \&JSON::Backend::XS::Supportable::_incr_parse; *{JSON::XS::_original_decode} = $JSON_XS_decode_orignal; *{JSON::XS::_original_encode} = $JSON_XS_encode_orignal; *{JSON::XS::_original_incr_parse} = $JSON_XS_incr_parse_orignal; push @JSON::Backend::XS::Supportable::ISA, 'JSON'; my $pkg = 'JSON::Backend::XS::Supportable'; *{JSON::new} = sub { my $proto = new JSON::XS; $$proto = 0; bless $proto, $pkg; }; for my $method (@methods) { my $flag = uc($method); my $type |= (UNSUPPORTED_ENCODE_FLAG->{$flag} || 0); $type |= (UNSUPPORTED_DECODE_FLAG->{$flag} || 0); next unless($type); $pkg->_make_unsupported_method($method => $type); } push @{"JSON::XS::Boolean::ISA"}, qw(JSON::PP::Boolean); push @{"JSON::PP::Boolean::ISA"}, qw(JSON::Boolean); $JSON::DEBUG and Carp::carp("set -support_by_pp mode."); return 1; } # # Helper classes for XS # package JSON::Backend::XS::Supportable; $Carp::Internal{'JSON::Backend::XS::Supportable'} = 1; sub _make_unsupported_method { my ($pkg, $method, $type) = @_; local $^W; no strict qw(refs); *{"$pkg\::$method"} = sub { local $^W; if (defined $_[1] ? $_[1] : 1) { ${$_[0]} |= $type; } else { ${$_[0]} &= ~$type; } $_[0]; }; *{"$pkg\::get_$method"} = sub { ${$_[0]} & $type ? 1 : ''; }; } sub _set_for_pp { JSON::_load_pp( $_INSTALL_ONLY ); my $type = shift; my $pp = new JSON::PP; my $prop = $_[0]->property; for my $name (keys %$prop) { $pp->$name( $prop->{$name} ? $prop->{$name} : 0 ); } my $unsupported = $type eq 'encode' ? JSON::Backend::XS::UNSUPPORTED_ENCODE_FLAG : JSON::Backend::XS::UNSUPPORTED_DECODE_FLAG; my $flags = ${$_[0]} || 0; for my $name (keys %$unsupported) { next if ($name eq 'EXPANDED'); # for developer's my $enable = ($flags & $unsupported->{$name}) ? 1 : 0; my $method = lc $name; $pp->$method($enable); } $pp->indent_length( $_[0]->get_indent_length ); return $pp; } sub _encode { # using with PP encod if (${$_[0]}) { _set_for_pp('encode' => @_)->encode($_[1]); } else { $_[0]->_original_encode( $_[1] ); } } sub _decode { # if unsupported-flag is set, use PP if (${$_[0]}) { _set_for_pp('decode' => @_)->decode($_[1]); } else { $_[0]->_original_decode( $_[1] ); } } sub decode_prefix { # if unsupported-flag is set, use PP _set_for_pp('decode' => @_)->decode_prefix($_[1]); } sub _incr_parse { if (${$_[0]}) { _set_for_pp('decode' => @_)->incr_parse($_[1]); } else { $_[0]->_original_incr_parse( $_[1] ); } } sub get_indent_length { ${$_[0]} << 4 >> 16; } sub indent_length { my $length = $_[1]; if (!defined $length or $length > 15 or $length < 0) { Carp::carp "The acceptable range of indent_length() is 0 to 15."; } else { local $^W; $length <<= 12; ${$_[0]} &= ~ JSON::Backend::XS::INDENT_LENGTH_FLAG; ${$_[0]} |= $length; *JSON::XS::encode = \&JSON::Backend::XS::Supportable::_encode; } $_[0]; } 1; __END__ =head1 NAME JSON - JSON (JavaScript Object Notation) encoder/decoder =head1 SYNOPSIS use JSON; # imports encode_json, decode_json, to_json and from_json. # simple and fast interfaces (expect/generate UTF-8) $utf8_encoded_json_text = encode_json $perl_hash_or_arrayref; $perl_hash_or_arrayref = decode_json $utf8_encoded_json_text; # OO-interface $json = JSON->new->allow_nonref; $json_text = $json->encode( $perl_scalar ); $perl_scalar = $json->decode( $json_text ); $pretty_printed = $json->pretty->encode( $perl_scalar ); # pretty-printing # If you want to use PP only support features, call with '-support_by_pp' # When XS unsupported feature is enable, using PP (de|en)code instead of XS ones. use JSON -support_by_pp; # option-acceptable interfaces (expect/generate UNICODE by default) $json_text = to_json( $perl_scalar, { ascii => 1, pretty => 1 } ); $perl_scalar = from_json( $json_text, { utf8 => 1 } ); # Between (en|de)code_json and (to|from)_json, if you want to write # a code which communicates to an outer world (encoded in UTF-8), # recommend to use (en|de)code_json. =head1 VERSION 2.53 This version is compatible with JSON::XS B<2.27> and later. =head1 NOTE JSON::PP was inculded in C distribution. It comes to be a perl core module in Perl 5.14. And L will be split away it. C distribution will inculde yet another JSON::PP modules. They are JSNO::backportPP and so on. JSON.pm should work as it did at all. =head1 DESCRIPTION ************************** CAUTION ******************************** * This is 'JSON module version 2' and there are many differences * * to version 1.xx * * Please check your applications useing old version. * * See to 'INCOMPATIBLE CHANGES TO OLD VERSION' * ******************************************************************* JSON (JavaScript Object Notation) is a simple data format. See to L and C(L). This module converts Perl data structures to JSON and vice versa using either L or L. JSON::XS is the fastest and most proper JSON module on CPAN which must be compiled and installed in your environment. JSON::PP is a pure-Perl module which is bundled in this distribution and has a strong compatibility to JSON::XS. This module try to use JSON::XS by default and fail to it, use JSON::PP instead. So its features completely depend on JSON::XS or JSON::PP. See to L. To distinguish the module name 'JSON' and the format type JSON, the former is quoted by CEE (its results vary with your using media), and the latter is left just as it is. Module name : C Format type : JSON =head2 FEATURES =over =item * correct unicode handling This module (i.e. backend modules) knows how to handle Unicode, documents how and when it does so, and even documents what "correct" means. Even though there are limitations, this feature is available since Perl version 5.6. JSON::XS requires Perl 5.8.2 (but works correctly in 5.8.8 or later), so in older versions C sholud call JSON::PP as the backend which can be used since Perl 5.005. With Perl 5.8.x JSON::PP works, but from 5.8.0 to 5.8.2, because of a Perl side problem, JSON::PP works slower in the versions. And in 5.005, the Unicode handling is not available. See to L for more information. See also to L and L. =item * round-trip integrity When you serialise a perl data structure using only data types supported by JSON and Perl, the deserialised data structure is identical on the Perl level. (e.g. the string "2.0" doesn't suddenly become "2" just because it looks like a number). There I minor exceptions to this, read the L section below to learn about those. =item * strict checking of JSON correctness There is no guessing, no generating of illegal JSON texts by default, and only JSON is accepted as input by default (the latter is a security feature). See to L and L. =item * fast This module returns a JSON::XS object itself if available. Compared to other JSON modules and other serialisers such as Storable, JSON::XS usually compares favourably in terms of speed, too. If not available, C returns a JSON::PP object instead of JSON::XS and it is very slow as pure-Perl. =item * simple to use This module has both a simple functional interface as well as an object oriented interface interface. =item * reasonably versatile output formats You can choose between the most compact guaranteed-single-line format possible (nice for simple line-based protocols), a pure-ASCII format (for when your transport is not 8-bit clean, still supports the whole Unicode range), or a pretty-printed format (for when you want to read that stuff). Or you can combine those features in whatever way you like. =back =head1 FUNCTIONAL INTERFACE Some documents are copied and modified from L. C and C are additional functions. =head2 encode_json $json_text = encode_json $perl_scalar Converts the given Perl data structure to a UTF-8 encoded, binary string. This function call is functionally identical to: $json_text = JSON->new->utf8->encode($perl_scalar) =head2 decode_json $perl_scalar = decode_json $json_text The opposite of C: expects an UTF-8 (binary) string and tries to parse that as an UTF-8 encoded JSON text, returning the resulting reference. This function call is functionally identical to: $perl_scalar = JSON->new->utf8->decode($json_text) =head2 to_json $json_text = to_json($perl_scalar) Converts the given Perl data structure to a json string. This function call is functionally identical to: $json_text = JSON->new->encode($perl_scalar) Takes a hash reference as the second. $json_text = to_json($perl_scalar, $flag_hashref) So, $json_text = to_json($perl_scalar, {utf8 => 1, pretty => 1}) equivalent to: $json_text = JSON->new->utf8(1)->pretty(1)->encode($perl_scalar) If you want to write a modern perl code which communicates to outer world, you should use C (supposed that JSON data are encoded in UTF-8). =head2 from_json $perl_scalar = from_json($json_text) The opposite of C: expects a json string and tries to parse it, returning the resulting reference. This function call is functionally identical to: $perl_scalar = JSON->decode($json_text) Takes a hash reference as the second. $perl_scalar = from_json($json_text, $flag_hashref) So, $perl_scalar = from_json($json_text, {utf8 => 1}) equivalent to: $perl_scalar = JSON->new->utf8(1)->decode($json_text) If you want to write a modern perl code which communicates to outer world, you should use C (supposed that JSON data are encoded in UTF-8). =head2 JSON::is_bool $is_boolean = JSON::is_bool($scalar) Returns true if the passed scalar represents either JSON::true or JSON::false, two constants that act like C<1> and C<0> respectively and are also used to represent JSON C and C in Perl strings. =head2 JSON::true Returns JSON true value which is blessed object. It C JSON::Boolean object. =head2 JSON::false Returns JSON false value which is blessed object. It C JSON::Boolean object. =head2 JSON::null Returns C. See L, below, for more information on how JSON values are mapped to Perl. =head1 HOW DO I DECODE A DATA FROM OUTER AND ENCODE TO OUTER This section supposes that your perl vresion is 5.8 or later. If you know a JSON text from an outer world - a network, a file content, and so on, is encoded in UTF-8, you should use C or C module object with C enable. And the decoded result will contain UNICODE characters. # from network my $json = JSON->new->utf8; my $json_text = CGI->new->param( 'json_data' ); my $perl_scalar = $json->decode( $json_text ); # from file content local $/; open( my $fh, '<', 'json.data' ); $json_text = <$fh>; $perl_scalar = decode_json( $json_text ); If an outer data is not encoded in UTF-8, firstly you should C it. use Encode; local $/; open( my $fh, '<', 'json.data' ); my $encoding = 'cp932'; my $unicode_json_text = decode( $encoding, <$fh> ); # UNICODE # or you can write the below code. # # open( my $fh, "<:encoding($encoding)", 'json.data' ); # $unicode_json_text = <$fh>; In this case, C<$unicode_json_text> is of course UNICODE string. So you B use C nor C module object with C enable. Instead of them, you use C module object with C disable or C. $perl_scalar = $json->utf8(0)->decode( $unicode_json_text ); # or $perl_scalar = from_json( $unicode_json_text ); Or C and C: $perl_scalar = decode_json( encode( 'utf8', $unicode_json_text ) ); # this way is not efficient. And now, you want to convert your C<$perl_scalar> into JSON data and send it to an outer world - a network or a file content, and so on. Your data usually contains UNICODE strings and you want the converted data to be encoded in UTF-8, you should use C or C module object with C enable. print encode_json( $perl_scalar ); # to a network? file? or display? # or print $json->utf8->encode( $perl_scalar ); If C<$perl_scalar> does not contain UNICODE but C<$encoding>-encoded strings for some reason, then its characters are regarded as B for perl (because it does not concern with your $encoding). You B use C nor C module object with C enable. Instead of them, you use C module object with C disable or C. Note that the resulted text is a UNICODE string but no problem to print it. # $perl_scalar contains $encoding encoded string values $unicode_json_text = $json->utf8(0)->encode( $perl_scalar ); # or $unicode_json_text = to_json( $perl_scalar ); # $unicode_json_text consists of characters less than 0x100 print $unicode_json_text; Or C all string values and C: $perl_scalar->{ foo } = decode( $encoding, $perl_scalar->{ foo } ); # ... do it to each string values, then encode_json $json_text = encode_json( $perl_scalar ); This method is a proper way but probably not efficient. See to L, L. =head1 COMMON OBJECT-ORIENTED INTERFACE =head2 new $json = new JSON Returns a new C object inherited from either JSON::XS or JSON::PP that can be used to de/encode JSON strings. All boolean flags described below are by default I. The mutators for flags all return the JSON object again and thus calls can be chained: my $json = JSON->new->utf8->space_after->encode({a => [1,2]}) => {"a": [1, 2]} =head2 ascii $json = $json->ascii([$enable]) $enabled = $json->get_ascii If $enable is true (or missing), then the encode method will not generate characters outside the code range 0..127. Any Unicode characters outside that range will be escaped using either a single \uXXXX or a double \uHHHH\uLLLLL escape sequence, as per RFC4627. If $enable is false, then the encode method will not escape Unicode characters unless required by the JSON syntax or other flags. This results in a faster and more compact format. This feature depends on the used Perl version and environment. See to L if the backend is PP. JSON->new->ascii(1)->encode([chr 0x10401]) => ["\ud801\udc01"] =head2 latin1 $json = $json->latin1([$enable]) $enabled = $json->get_latin1 If $enable is true (or missing), then the encode method will encode the resulting JSON text as latin1 (or iso-8859-1), escaping any characters outside the code range 0..255. If $enable is false, then the encode method will not escape Unicode characters unless required by the JSON syntax or other flags. JSON->new->latin1->encode (["\x{89}\x{abc}"] => ["\x{89}\\u0abc"] # (perl syntax, U+abc escaped, U+89 not) =head2 utf8 $json = $json->utf8([$enable]) $enabled = $json->get_utf8 If $enable is true (or missing), then the encode method will encode the JSON result into UTF-8, as required by many protocols, while the decode method expects to be handled an UTF-8-encoded string. Please note that UTF-8-encoded strings do not contain any characters outside the range 0..255, they are thus useful for bytewise/binary I/O. In future versions, enabling this option might enable autodetection of the UTF-16 and UTF-32 encoding families, as described in RFC4627. If $enable is false, then the encode method will return the JSON string as a (non-encoded) Unicode string, while decode expects thus a Unicode string. Any decoding or encoding (e.g. to UTF-8 or UTF-16) needs to be done yourself, e.g. using the Encode module. Example, output UTF-16BE-encoded JSON: use Encode; $jsontext = encode "UTF-16BE", JSON::XS->new->encode ($object); Example, decode UTF-32LE-encoded JSON: use Encode; $object = JSON::XS->new->decode (decode "UTF-32LE", $jsontext); See to L if the backend is PP. =head2 pretty $json = $json->pretty([$enable]) This enables (or disables) all of the C, C and C (and in the future possibly more) flags in one call to generate the most readable (or most compact) form possible. Equivalent to: $json->indent->space_before->space_after The indent space length is three and JSON::XS cannot change the indent space length. =head2 indent $json = $json->indent([$enable]) $enabled = $json->get_indent If C<$enable> is true (or missing), then the C method will use a multiline format as output, putting every array member or object/hash key-value pair into its own line, identing them properly. If C<$enable> is false, no newlines or indenting will be produced, and the resulting JSON text is guarenteed not to contain any C. This setting has no effect when decoding JSON texts. The indent space length is three. With JSON::PP, you can also access C to change indent space length. =head2 space_before $json = $json->space_before([$enable]) $enabled = $json->get_space_before If C<$enable> is true (or missing), then the C method will add an extra optional space before the C<:> separating keys from values in JSON objects. If C<$enable> is false, then the C method will not add any extra space at those places. This setting has no effect when decoding JSON texts. Example, space_before enabled, space_after and indent disabled: {"key" :"value"} =head2 space_after $json = $json->space_after([$enable]) $enabled = $json->get_space_after If C<$enable> is true (or missing), then the C method will add an extra optional space after the C<:> separating keys from values in JSON objects and extra whitespace after the C<,> separating key-value pairs and array members. If C<$enable> is false, then the C method will not add any extra space at those places. This setting has no effect when decoding JSON texts. Example, space_before and indent disabled, space_after enabled: {"key": "value"} =head2 relaxed $json = $json->relaxed([$enable]) $enabled = $json->get_relaxed If C<$enable> is true (or missing), then C will accept some extensions to normal JSON syntax (see below). C will not be affected in anyway. I. I suggest only to use this option to parse application-specific files written by humans (configuration files, resource files etc.) If C<$enable> is false (the default), then C will only accept valid JSON texts. Currently accepted extensions are: =over 4 =item * list items can have an end-comma JSON I array elements and key-value pairs with commas. This can be annoying if you write JSON texts manually and want to be able to quickly append elements, so this extension accepts comma at the end of such items not just between them: [ 1, 2, <- this comma not normally allowed ] { "k1": "v1", "k2": "v2", <- this comma not normally allowed } =item * shell-style '#'-comments Whenever JSON allows whitespace, shell-style comments are additionally allowed. They are terminated by the first carriage-return or line-feed character, after which more white-space and comments are allowed. [ 1, # this comment not allowed in JSON # neither this one... ] =back =head2 canonical $json = $json->canonical([$enable]) $enabled = $json->get_canonical If C<$enable> is true (or missing), then the C method will output JSON objects by sorting their keys. This is adding a comparatively high overhead. If C<$enable> is false, then the C method will output key-value pairs in the order Perl stores them (which will likely change between runs of the same script). This option is useful if you want the same data structure to be encoded as the same JSON text (given the same overall settings). If it is disabled, the same hash might be encoded differently even if contains the same data, as key-value pairs have no inherent ordering in Perl. This setting has no effect when decoding JSON texts. =head2 allow_nonref $json = $json->allow_nonref([$enable]) $enabled = $json->get_allow_nonref If C<$enable> is true (or missing), then the C method can convert a non-reference into its corresponding string, number or null JSON value, which is an extension to RFC4627. Likewise, C will accept those JSON values instead of croaking. If C<$enable> is false, then the C method will croak if it isn't passed an arrayref or hashref, as JSON texts must either be an object or array. Likewise, C will croak if given something that is not a JSON object or array. JSON->new->allow_nonref->encode ("Hello, World!") => "Hello, World!" =head2 allow_unknown $json = $json->allow_unknown ([$enable]) $enabled = $json->get_allow_unknown If $enable is true (or missing), then "encode" will *not* throw an exception when it encounters values it cannot represent in JSON (for example, filehandles) but instead will encode a JSON "null" value. Note that blessed objects are not included here and are handled separately by c. If $enable is false (the default), then "encode" will throw an exception when it encounters anything it cannot encode as JSON. This option does not affect "decode" in any way, and it is recommended to leave it off unless you know your communications partner. =head2 allow_blessed $json = $json->allow_blessed([$enable]) $enabled = $json->get_allow_blessed If C<$enable> is true (or missing), then the C method will not barf when it encounters a blessed reference. Instead, the value of the B option will decide whether C (C disabled or no C method found) or a representation of the object (C enabled and C method found) is being encoded. Has no effect on C. If C<$enable> is false (the default), then C will throw an exception when it encounters a blessed object. =head2 convert_blessed $json = $json->convert_blessed([$enable]) $enabled = $json->get_convert_blessed If C<$enable> is true (or missing), then C, upon encountering a blessed object, will check for the availability of the C method on the object's class. If found, it will be called in scalar context and the resulting scalar will be encoded instead of the object. If no C method is found, the value of C will decide what to do. The C method may safely call die if it wants. If C returns other blessed objects, those will be handled in the same way. C must take care of not causing an endless recursion cycle (== crash) in this case. The name of C was chosen because other methods called by the Perl core (== not by the user of the object) are usually in upper case letters and to avoid collisions with the C function or method. This setting does not yet influence C in any way. If C<$enable> is false, then the C setting will decide what to do when a blessed object is found. =over =item convert_blessed_universally mode If use C with C<-convert_blessed_universally>, the C subroutine is defined as the below code: *UNIVERSAL::TO_JSON = sub { my $b_obj = B::svref_2object( $_[0] ); return $b_obj->isa('B::HV') ? { %{ $_[0] } } : $b_obj->isa('B::AV') ? [ @{ $_[0] } ] : undef ; } This will cause that C method converts simple blessed objects into JSON objects as non-blessed object. JSON -convert_blessed_universally; $json->allow_blessed->convert_blessed->encode( $blessed_object ) This feature is experimental and may be removed in the future. =back =head2 filter_json_object $json = $json->filter_json_object([$coderef]) When C<$coderef> is specified, it will be called from C each time it decodes a JSON object. The only argument passed to the coderef is a reference to the newly-created hash. If the code references returns a single scalar (which need not be a reference), this value (i.e. a copy of that scalar to avoid aliasing) is inserted into the deserialised data structure. If it returns an empty list (NOTE: I C, which is a valid scalar), the original deserialised hash will be inserted. This setting can slow down decoding considerably. When C<$coderef> is omitted or undefined, any existing callback will be removed and C will not change the deserialised hash in any way. Example, convert all JSON objects into the integer 5: my $js = JSON->new->filter_json_object (sub { 5 }); # returns [5] $js->decode ('[{}]'); # the given subroutine takes a hash reference. # throw an exception because allow_nonref is not enabled # so a lone 5 is not allowed. $js->decode ('{"a":1, "b":2}'); =head2 filter_json_single_key_object $json = $json->filter_json_single_key_object($key [=> $coderef]) Works remotely similar to C, but is only called for JSON objects having a single key named C<$key>. This C<$coderef> is called before the one specified via C, if any. It gets passed the single value in the JSON object. If it returns a single value, it will be inserted into the data structure. If it returns nothing (not even C but the empty list), the callback from C will be called next, as if no single-key callback were specified. If C<$coderef> is omitted or undefined, the corresponding callback will be disabled. There can only ever be one callback for a given key. As this callback gets called less often then the C one, decoding speed will not usually suffer as much. Therefore, single-key objects make excellent targets to serialise Perl objects into, especially as single-key JSON objects are as close to the type-tagged value concept as JSON gets (it's basically an ID/VALUE tuple). Of course, JSON does not support this in any way, so you need to make sure your data never looks like a serialised Perl hash. Typical names for the single object key are C<__class_whatever__>, or C<$__dollars_are_rarely_used__$> or C<}ugly_brace_placement>, or even things like C<__class_md5sum(classname)__>, to reduce the risk of clashing with real hashes. Example, decode JSON objects of the form C<< { "__widget__" => } >> into the corresponding C<< $WIDGET{} >> object: # return whatever is in $WIDGET{5}: JSON ->new ->filter_json_single_key_object (__widget__ => sub { $WIDGET{ $_[0] } }) ->decode ('{"__widget__": 5') # this can be used with a TO_JSON method in some "widget" class # for serialisation to json: sub WidgetBase::TO_JSON { my ($self) = @_; unless ($self->{id}) { $self->{id} = ..get..some..id..; $WIDGET{$self->{id}} = $self; } { __widget__ => $self->{id} } } =head2 shrink $json = $json->shrink([$enable]) $enabled = $json->get_shrink With JSON::XS, this flag resizes strings generated by either C or C to their minimum size possible. This can save memory when your JSON texts are either very very long or you have many short strings. It will also try to downgrade any strings to octet-form if possible: perl stores strings internally either in an encoding called UTF-X or in octet-form. The latter cannot store everything but uses less space in general (and some buggy Perl or C code might even rely on that internal representation being used). With JSON::PP, it is noop about resizing strings but tries C to the returned string by C. See to L. See to L and L. =head2 max_depth $json = $json->max_depth([$maximum_nesting_depth]) $max_depth = $json->get_max_depth Sets the maximum nesting level (default C<512>) accepted while encoding or decoding. If a higher nesting level is detected in JSON text or a Perl data structure, then the encoder and decoder will stop and croak at that point. Nesting level is defined by number of hash- or arrayrefs that the encoder needs to traverse to reach a given point or the number of C<{> or C<[> characters without their matching closing parenthesis crossed to reach a given character in a string. If no argument is given, the highest possible setting will be used, which is rarely useful. Note that nesting is implemented by recursion in C. The default value has been chosen to be as large as typical operating systems allow without crashing. (JSON::XS) With JSON::PP as the backend, when a large value (100 or more) was set and it de/encodes a deep nested object/text, it may raise a warning 'Deep recursion on subroutin' at the perl runtime phase. See L for more info on why this is useful. =head2 max_size $json = $json->max_size([$maximum_string_size]) $max_size = $json->get_max_size Set the maximum length a JSON text may have (in bytes) where decoding is being attempted. The default is C<0>, meaning no limit. When C is called on a string that is longer then this many bytes, it will not attempt to decode the string but throw an exception. This setting has no effect on C (yet). If no argument is given, the limit check will be deactivated (same as when C<0> is specified). See L, below, for more info on why this is useful. =head2 encode $json_text = $json->encode($perl_scalar) Converts the given Perl data structure (a simple scalar or a reference to a hash or array) to its JSON representation. Simple scalars will be converted into JSON string or number sequences, while references to arrays become JSON arrays and references to hashes become JSON objects. Undefined Perl values (e.g. C) become JSON C values. References to the integers C<0> and C<1> are converted into C and C. =head2 decode $perl_scalar = $json->decode($json_text) The opposite of C: expects a JSON text and tries to parse it, returning the resulting simple scalar or reference. Croaks on error. JSON numbers and strings become simple Perl scalars. JSON arrays become Perl arrayrefs and JSON objects become Perl hashrefs. C becomes C<1> (C), C becomes C<0> (C) and C becomes C. =head2 decode_prefix ($perl_scalar, $characters) = $json->decode_prefix($json_text) This works like the C method, but instead of raising an exception when there is trailing garbage after the first JSON object, it will silently stop parsing there and return the number of characters consumed so far. JSON->new->decode_prefix ("[1] the tail") => ([], 3) See to L =head2 property $boolean = $json->property($property_name) Returns a boolean value about above some properties. The available properties are C, C, C, C,C, C, C, C, C, C, C, C, C, C and C. $boolean = $json->property('utf8'); => 0 $json->utf8; $boolean = $json->property('utf8'); => 1 Sets the property with a given boolean value. $json = $json->property($property_name => $boolean); With no argumnt, it returns all the above properties as a hash reference. $flag_hashref = $json->property(); =head1 INCREMENTAL PARSING Most of this section are copied and modified from L. In some cases, there is the need for incremental parsing of JSON texts. This module does allow you to parse a JSON stream incrementally. It does so by accumulating text until it has a full JSON object, which it then can decode. This process is similar to using C to see if a full JSON object is available, but is much more efficient (and can be implemented with a minimum of method calls). The backend module will only attempt to parse the JSON text once it is sure it has enough text to get a decisive result, using a very simple but truly incremental parser. This means that it sometimes won't stop as early as the full parser, for example, it doesn't detect parenthese mismatches. The only thing it guarantees is that it starts decoding as soon as a syntactically valid JSON text has been seen. This means you need to set resource limits (e.g. C) to ensure the parser will stop parsing in the presence if syntax errors. The following methods implement this incremental parser. =head2 incr_parse $json->incr_parse( [$string] ) # void context $obj_or_undef = $json->incr_parse( [$string] ) # scalar context @obj_or_empty = $json->incr_parse( [$string] ) # list context This is the central parsing function. It can both append new text and extract objects from the stream accumulated so far (both of these functions are optional). If C<$string> is given, then this string is appended to the already existing JSON fragment stored in the C<$json> object. After that, if the function is called in void context, it will simply return without doing anything further. This can be used to add more text in as many chunks as you want. If the method is called in scalar context, then it will try to extract exactly I JSON object. If that is successful, it will return this object, otherwise it will return C. If there is a parse error, this method will croak just as C would do (one can then use C to skip the errornous part). This is the most common way of using the method. And finally, in list context, it will try to extract as many objects from the stream as it can find and return them, or the empty list otherwise. For this to work, there must be no separators between the JSON objects or arrays, instead they must be concatenated back-to-back. If an error occurs, an exception will be raised as in the scalar context case. Note that in this case, any previously-parsed JSON texts will be lost. Example: Parse some JSON arrays/objects in a given string and return them. my @objs = JSON->new->incr_parse ("[5][7][1,2]"); =head2 incr_text $lvalue_string = $json->incr_text This method returns the currently stored JSON fragment as an lvalue, that is, you can manipulate it. This I works when a preceding call to C in I successfully returned an object. Under all other circumstances you must not call this function (I mean it. although in simple tests it might actually work, it I fail under real world conditions). As a special exception, you can also call this method before having parsed anything. This function is useful in two cases: a) finding the trailing text after a JSON object or b) parsing multiple JSON objects separated by non-JSON text (such as commas). $json->incr_text =~ s/\s*,\s*//; In Perl 5.005, C attribute is not available. You must write codes like the below: $string = $json->incr_text; $string =~ s/\s*,\s*//; $json->incr_text( $string ); =head2 incr_skip $json->incr_skip This will reset the state of the incremental parser and will remove the parsed text from the input buffer. This is useful after C died, in which case the input buffer and incremental parser state is left unchanged, to skip the text parsed so far and to reset the parse state. =head2 incr_reset $json->incr_reset This completely resets the incremental parser, that is, after this call, it will be as if the parser had never parsed anything. This is useful if you want ot repeatedly parse JSON objects and want to ignore any trailing data, which means you have to reset the parser after each successful decode. See to L for examples. =head1 JSON::PP SUPPORT METHODS The below methods are JSON::PP own methods, so when C works with JSON::PP (i.e. the created object is a JSON::PP object), available. See to L in detail. If you use C with additonal C<-support_by_pp>, some methods are available even with JSON::XS. See to L. BEING { $ENV{PERL_JSON_BACKEND} = 'JSON::XS' } use JSON -support_by_pp; my $json = new JSON; $json->allow_nonref->escape_slash->encode("/"); # functional interfaces too. print to_json(["/"], {escape_slash => 1}); print from_json('["foo"]', {utf8 => 1}); If you do not want to all functions but C<-support_by_pp>, use C<-no_export>. use JSON -support_by_pp, -no_export; # functional interfaces are not exported. =head2 allow_singlequote $json = $json->allow_singlequote([$enable]) If C<$enable> is true (or missing), then C will accept any JSON strings quoted by single quotations that are invalid JSON format. $json->allow_singlequote->decode({"foo":'bar'}); $json->allow_singlequote->decode({'foo':"bar"}); $json->allow_singlequote->decode({'foo':'bar'}); As same as the C option, this option may be used to parse application-specific files written by humans. =head2 allow_barekey $json = $json->allow_barekey([$enable]) If C<$enable> is true (or missing), then C will accept bare keys of JSON object that are invalid JSON format. As same as the C option, this option may be used to parse application-specific files written by humans. $json->allow_barekey->decode('{foo:"bar"}'); =head2 allow_bignum $json = $json->allow_bignum([$enable]) If C<$enable> is true (or missing), then C will convert the big integer Perl cannot handle as integer into a L object and convert a floating number (any) into a L. On the contary, C converts C objects and C objects into JSON numbers with C enable. $json->allow_nonref->allow_blessed->allow_bignum; $bigfloat = $json->decode('2.000000000000000000000000001'); print $json->encode($bigfloat); # => 2.000000000000000000000000001 See to L aboout the conversion of JSON number. =head2 loose $json = $json->loose([$enable]) The unescaped [\x00-\x1f\x22\x2f\x5c] strings are invalid in JSON strings and the module doesn't allow to C to these (except for \x2f). If C<$enable> is true (or missing), then C will accept these unescaped strings. $json->loose->decode(qq|["abc def"]|); See to L. =head2 escape_slash $json = $json->escape_slash([$enable]) According to JSON Grammar, I (U+002F) is escaped. But by default JSON backend modules encode strings without escaping slash. If C<$enable> is true (or missing), then C will escape slashes. =head2 indent_length $json = $json->indent_length($length) With JSON::XS, The indent space length is 3 and cannot be changed. With JSON::PP, it sets the indent space length with the given $length. The default is 3. The acceptable range is 0 to 15. =head2 sort_by $json = $json->sort_by($function_name) $json = $json->sort_by($subroutine_ref) If $function_name or $subroutine_ref are set, its sort routine are used. $js = $pc->sort_by(sub { $JSON::PP::a cmp $JSON::PP::b })->encode($obj); # is($js, q|{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9}|); $js = $pc->sort_by('own_sort')->encode($obj); # is($js, q|{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9}|); sub JSON::PP::own_sort { $JSON::PP::a cmp $JSON::PP::b } As the sorting routine runs in the JSON::PP scope, the given subroutine name and the special variables C<$a>, C<$b> will begin with 'JSON::PP::'. If $integer is set, then the effect is same as C on. See to L. =head1 MAPPING This section is copied from JSON::XS and modified to C. JSON::XS and JSON::PP mapping mechanisms are almost equivalent. See to L. =head2 JSON -> PERL =over 4 =item object A JSON object becomes a reference to a hash in Perl. No ordering of object keys is preserved (JSON does not preserver object key ordering itself). =item array A JSON array becomes a reference to an array in Perl. =item string A JSON string becomes a string scalar in Perl - Unicode codepoints in JSON are represented by the same codepoints in the Perl string, so no manual decoding is necessary. =item number A JSON number becomes either an integer, numeric (floating point) or string scalar in perl, depending on its range and any fractional parts. On the Perl level, there is no difference between those as Perl handles all the conversion details, but an integer may take slightly less memory and might represent more values exactly than floating point numbers. If the number consists of digits only, C will try to represent it as an integer value. If that fails, it will try to represent it as a numeric (floating point) value if that is possible without loss of precision. Otherwise it will preserve the number as a string value (in which case you lose roundtripping ability, as the JSON number will be re-encoded toa JSON string). Numbers containing a fractional or exponential part will always be represented as numeric (floating point) values, possibly at a loss of precision (in which case you might lose perfect roundtripping ability, but the JSON number will still be re-encoded as a JSON number). Note that precision is not accuracy - binary floating point values cannot represent most decimal fractions exactly, and when converting from and to floating point, C only guarantees precision up to but not including the leats significant bit. If the backend is JSON::PP and C is enable, the big integers and the numeric can be optionally converted into L and L objects. =item true, false These JSON atoms become C and C, respectively. They are overloaded to act almost exactly like the numbers C<1> and C<0>. You can check wether a scalar is a JSON boolean by using the C function. If C and C are used as strings or compared as strings, they represent as C and C respectively. print JSON::true . "\n"; => true print JSON::true + 1; => 1 ok(JSON::true eq 'true'); ok(JSON::true eq '1'); ok(JSON::true == 1); C will install these missing overloading features to the backend modules. =item null A JSON null atom becomes C in Perl. C returns C. =back =head2 PERL -> JSON The mapping from Perl to JSON is slightly more difficult, as Perl is a truly typeless language, so we can only guess which JSON type is meant by a Perl value. =over 4 =item hash references Perl hash references become JSON objects. As there is no inherent ordering in hash keys (or JSON objects), they will usually be encoded in a pseudo-random order that can change between runs of the same program but stays generally the same within a single run of a program. C optionally sort the hash keys (determined by the I flag), so the same datastructure will serialise to the same JSON text (given same settings and version of JSON::XS), but this incurs a runtime overhead and is only rarely useful, e.g. when you want to compare some JSON text against another for equality. In future, the ordered object feature will be added to JSON::PP using C mechanism. =item array references Perl array references become JSON arrays. =item other references Other unblessed references are generally not allowed and will cause an exception to be thrown, except for references to the integers C<0> and C<1>, which get turned into C and C atoms in JSON. You can also use C and C to improve readability. to_json [\0,JSON::true] # yields [false,true] =item JSON::true, JSON::false, JSON::null These special values become JSON true and JSON false values, respectively. You can also use C<\1> and C<\0> directly if you want. JSON::null returns C. =item blessed objects Blessed objects are not directly representable in JSON. See the C and C methods on various options on how to deal with this: basically, you can choose between throwing an exception, encoding the reference as if it weren't blessed, or provide your own serialiser method. With C mode, C converts blessed hash references or blessed array references (contains other blessed references) into JSON members and arrays. use JSON -convert_blessed_universally; JSON->new->allow_blessed->convert_blessed->encode( $blessed_object ); See to L. =item simple scalars Simple Perl scalars (any scalar that is not a reference) are the most difficult objects to encode: JSON::XS and JSON::PP will encode undefined scalars as JSON C values, scalars that have last been used in a string context before encoding as JSON strings, and anything else as number value: # dump as number encode_json [2] # yields [2] encode_json [-3.0e17] # yields [-3e+17] my $value = 5; encode_json [$value] # yields [5] # used as string, so dump as string print $value; encode_json [$value] # yields ["5"] # undef becomes null encode_json [undef] # yields [null] You can force the type to be a string by stringifying it: my $x = 3.1; # some variable containing a number "$x"; # stringified $x .= ""; # another, more awkward way to stringify print $x; # perl does it for you, too, quite often You can force the type to be a number by numifying it: my $x = "3"; # some variable containing a string $x += 0; # numify it, ensuring it will be dumped as a number $x *= 1; # same thing, the choise is yours. You can not currently force the type in other, less obscure, ways. Note that numerical precision has the same meaning as under Perl (so binary to decimal conversion follows the same rules as in Perl, which can differ to other languages). Also, your perl interpreter might expose extensions to the floating point numbers of your platform, such as infinities or NaN's - these cannot be represented in JSON, and it is an error to pass those in. =item Big Number If the backend is JSON::PP and C is enable, C converts C objects and C objects into JSON numbers. =back =head1 JSON and ECMAscript See to L. =head1 JSON and YAML JSON is not a subset of YAML. See to L. =head1 BACKEND MODULE DECISION When you use C, C tries to C JSON::XS. If this call failed, it will C JSON::PP. The required JSON::XS version is I<2.2> or later. The C constructor method returns an object inherited from the backend module, and JSON::XS object is a blessed scaler reference while JSON::PP is a blessed hash reference. So, your program should not depend on the backend module, especially returned objects should not be modified. my $json = JSON->new; # XS or PP? $json->{stash} = 'this is xs object'; # this code may raise an error! To check the backend module, there are some methods - C, C and C. JSON->backend; # 'JSON::XS' or 'JSON::PP' JSON->backend->is_pp: # 0 or 1 JSON->backend->is_xs: # 1 or 0 $json->is_xs; # 1 or 0 $json->is_pp; # 0 or 1 If you set an enviornment variable C, The calling action will be changed. =over =item PERL_JSON_BACKEND = 0 or PERL_JSON_BACKEND = 'JSON::PP' Always use JSON::PP =item PERL_JSON_BACKEND == 1 or PERL_JSON_BACKEND = 'JSON::XS,JSON::PP' (The default) Use compiled JSON::XS if it is properly compiled & installed, otherwise use JSON::PP. =item PERL_JSON_BACKEND == 2 or PERL_JSON_BACKEND = 'JSON::XS' Always use compiled JSON::XS, die if it isn't properly compiled & installed. =item PERL_JSON_BACKEND = 'JSON::backportPP' Always use JSON::backportPP. JSON::backportPP is JSON::PP back port module. C includs JSON::backportPP instead of JSON::PP. =back These ideas come from L mechanism. example: BEGIN { $ENV{PERL_JSON_BACKEND} = 'JSON::PP' } use JSON; # always uses JSON::PP In future, it may be able to specify another module. =head1 USE PP FEATURES EVEN THOUGH XS BACKEND Many methods are available with either JSON::XS or JSON::PP and when the backend module is JSON::XS, if any JSON::PP specific (i.e. JSON::XS unspported) method is called, it will C and be noop. But If you C C passing the optional string C<-support_by_pp>, it makes a part of those unupported methods available. This feature is achieved by using JSON::PP in C. BEGIN { $ENV{PERL_JSON_BACKEND} = 2 } # with JSON::XS use JSON -support_by_pp; my $json = new JSON; $json->allow_nonref->escape_slash->encode("/"); At this time, the returned object is a C object (re-blessed XS object), and by checking JSON::XS unsupported flags in de/encoding, can support some unsupported methods - C, C, C, C, C and C. When any unsupported methods are not enable, C will be used as is. The switch is achieved by changing the symbolic tables. C<-support_by_pp> is effective only when the backend module is JSON::XS and it makes the de/encoding speed down a bit. See to L. =head1 INCOMPATIBLE CHANGES TO OLD VERSION There are big incompatibility between new version (2.00) and old (1.xx). If you use old C 1.xx in your code, please check it. See to L =over =item jsonToObj and objToJson are obsoleted. Non Perl-style name C and C are obsoleted (but not yet deleted from the source). If you use these functions in your code, please replace them with C and C. =item Global variables are no longer available. C class variables - C<$JSON::AUTOCONVERT>, C<$JSON::BareKey>, etc... - are not available any longer. Instead, various features can be used through object methods. =item Package JSON::Converter and JSON::Parser are deleted. Now C bundles with JSON::PP which can handle JSON more properly than them. =item Package JSON::NotString is deleted. There was C class which represents JSON value C, C, C and numbers. It was deleted and replaced by C. C represents C and C. C does not represent C. C returns C. C makes L and L is-a relation to L. =item function JSON::Number is obsoleted. C is now needless because JSON::XS and JSON::PP have round-trip integrity. =item JSONRPC modules are deleted. Perl implementation of JSON-RPC protocol - C, C and C are deleted in this distribution. Instead of them, there is L which supports JSON-RPC protocol version 1.1. =back =head2 Transition ways from 1.xx to 2.xx. You should set C mode firstly, because it is always successful for the below codes even with JSON::XS. use JSON -support_by_pp; =over =item Exported jsonToObj (simple) from_json($json_text); =item Exported objToJson (simple) to_json($perl_scalar); =item Exported jsonToObj (advanced) $flags = {allow_barekey => 1, allow_singlequote => 1}; from_json($json_text, $flags); equivalent to: $JSON::BareKey = 1; $JSON::QuotApos = 1; jsonToObj($json_text); =item Exported objToJson (advanced) $flags = {allow_blessed => 1, allow_barekey => 1}; to_json($perl_scalar, $flags); equivalent to: $JSON::BareKey = 1; objToJson($perl_scalar); =item jsonToObj as object method $json->decode($json_text); =item objToJson as object method $json->encode($perl_scalar); =item new method with parameters The C method in 2.x takes any parameters no longer. You can set parameters instead; $json = JSON->new->pretty; =item $JSON::Pretty, $JSON::Indent, $JSON::Delimiter If C is enable, that means C<$JSON::Pretty> flag set. And C<$JSON::Delimiter> was substituted by C and C. In conclusion: $json->indent->space_before->space_after; Equivalent to: $json->pretty; To change indent length, use C. (Only with JSON::PP, if C<-support_by_pp> is not used.) $json->pretty->indent_length(2)->encode($perl_scalar); =item $JSON::BareKey (Only with JSON::PP, if C<-support_by_pp> is not used.) $json->allow_barekey->decode($json_text) =item $JSON::ConvBlessed use C<-convert_blessed_universally>. See to L. =item $JSON::QuotApos (Only with JSON::PP, if C<-support_by_pp> is not used.) $json->allow_singlequote->decode($json_text) =item $JSON::SingleQuote Disable. C does not make such a invalid JSON string any longer. =item $JSON::KeySort $json->canonical->encode($perl_scalar) This is the ascii sort. If you want to use with your own sort routine, check the C method. (Only with JSON::PP, even if C<-support_by_pp> is used currently.) $json->sort_by($sort_routine_ref)->encode($perl_scalar) $json->sort_by(sub { $JSON::PP::a <=> $JSON::PP::b })->encode($perl_scalar) Can't access C<$a> and C<$b> but C<$JSON::PP::a> and C<$JSON::PP::b>. =item $JSON::SkipInvalid $json->allow_unknown =item $JSON::AUTOCONVERT Needless. C backend modules have the round-trip integrity. =item $JSON::UTF8 Needless because C (JSON::XS/JSON::PP) sets the UTF8 flag on properly. # With UTF8-flagged strings $json->allow_nonref; $str = chr(1000); # UTF8-flagged $json_text = $json->utf8(0)->encode($str); utf8::is_utf8($json_text); # true $json_text = $json->utf8(1)->encode($str); utf8::is_utf8($json_text); # false $str = '"' . chr(1000) . '"'; # UTF8-flagged $perl_scalar = $json->utf8(0)->decode($str); utf8::is_utf8($perl_scalar); # true $perl_scalar = $json->utf8(1)->decode($str); # died because of 'Wide character in subroutine' See to L. =item $JSON::UnMapping Disable. See to L. =item $JSON::SelfConvert This option was deleted. Instead of it, if a givien blessed object has the C method, C will be executed with C. $json->convert_blessed->encode($bleesed_hashref_or_arrayref) # if need, call allow_blessed Note that it was C in old version, but now not C but C. =back =head1 TODO =over =item example programs =back =head1 THREADS No test with JSON::PP. If with JSON::XS, See to L. =head1 BUGS Please report bugs relevant to C to Emakamaka[at]cpan.orgE. =head1 SEE ALSO Most of the document is copied and modified from JSON::XS doc. L, L C(L) =head1 AUTHOR Makamaka Hannyaharamitu, Emakamaka[at]cpan.orgE JSON::XS was written by Marc Lehmann The relese of this new version owes to the courtesy of Marc Lehmann. =head1 COPYRIGHT AND LICENSE Copyright 2005-2011 by Makamaka Hannyaharamitu This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut ================================================ FILE: tools/Makefile ================================================ # SPDX-License-Identifier: Apache-2.0 # Copyright 2020 Western Digital Corporation or its affiliates. # Copyright 2024 Antmicro # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ifeq ($(USER_MODE),1) USER_MODE_OPTS = -set=user_mode=1 else USER_MODE_OPTS = endif CONF_PARAMS ?= -set build_axi4 $(USER_MODE_OPTS) TEST_CFLAGS = -g -gdwarf -O3 -funroll-all-loops ABI = -mabi=ilp32 LD_ABI = $(ABI) -march=rv32imac TB_EXTRA_ARGS ?= --test-halt # Check for RV_ROOT ifeq (,$(wildcard ${RV_ROOT}/configs/veer.config)) $(error env var RV_ROOT does not point to a valid dir! Exiting!) endif # Allow snapshot override target = default snapshot = $(target) # Allow tool override VEER_CONFIG = ${RV_ROOT}/configs/veer.config IRUN = xrun VCS = vcs VLOG = qverilog VERILATOR = verilator RIVIERA = riviera GCC_PREFIX = riscv64-unknown-elf BUILD_DIR = snapshots/${snapshot} TBDIR = ${RV_ROOT}/testbench PICOLIBC_DIR = ${RV_ROOT}/third_party/picolibc/install # Override march depending on used GCC version ifneq ($(shell which $(GCC_PREFIX)-gcc 2> /dev/null),) GCCVERSIONGT11 := $(shell expr `$(GCC_PREFIX)-gcc -dumpversion | cut -f1 -d.` \>= 11) ifeq "$(GCCVERSIONGT11)" "1" CC_ABI = $(ABI) -march=rv32imc_zicsr_zifencei_zba_zbb_zbc_zbs else CC_ABI = $(ABI) -march=rv32imc endif endif # Determine verilator version if possible. Set the flag accordingly. Since # version v5.006 -Wno-IMPLICIT was renamed to -Wno-IMPLICITSTATIC VERILATOR_NOIMPLICIT := -Wno-IMPLICITSTATIC VERILATOR_VERSION := $(subst .,,$(word 2,$(shell $(VERILATOR) --version))) ifneq ($(TB_MAX_CYCLES),) VERILATOR_EXTRA_ARGS := -GMAX_CYCLES=$(TB_MAX_CYCLES) endif ifeq ("$(.SHELLSTATUS)", "0") $(shell test $(VERILATOR_VERSION) -lt 5006) ifeq ("$(.SHELLSTATUS)", "0") VERILATOR_NOIMPLICIT := -Wno-IMPLICIT endif endif VERILATOR_SKIP_WARNINGS = $(VERILATOR_NOIMPLICIT) -Wno-TIMESCALEMOD -Wno-ASCRANGE \ -Wno-CASEINCOMPLETE -Wno-INITIALDLY -Wno-WIDTH -Wno-UNOPTFLAT -Wno-SIDEEFFECT \ -Wno-LATCH # Define test name TEST = hello_world TEST_DIR = ${TBDIR}/asm HEX_DIR = ${TBDIR}/hex # Coverage reporting # TODO: Set flags for other tools here as well ifeq ("$(COVERAGE)", "all") VERILATOR_COVERAGE = --coverage else ifeq ("$(COVERAGE)", "branch") VERILATOR_COVERAGE = --coverage-line else ifeq ("$(COVERAGE)", "toggle") VERILATOR_COVERAGE = --coverage-toggle else ifeq ("$(COVERAGE)", "functional") VERILATOR_COVERAGE = --coverage-user else ifneq ("$(COVERAGE)", "") $(error Unknown COVERAGE value '$(COVERAGE)') endif # Determine test directory ifneq (,$(wildcard $(TBDIR)/tests/$(TEST))) TEST_DIR = $(TBDIR)/tests/$(TEST) endif OFILES = $(TEST).o ifdef debug DEBUG_PLUS = +dumpon IRUN_DEBUG = -access +rc IRUN_DEBUG_RUN = -input ${RV_ROOT}/testbench/input.tcl VCS_DEBUG = -debug_access VERILATOR_DEBUG = --trace RIVIERA_DEBUG = +access +r endif ifdef assert ASSERT_DEFINES = +define+RV_ASSERT_ON endif # Prevent testbench from returning a non-zero exit code ifdef tb_silent_fail TB_SILENT_FAIL = +define+TB_SILENT_FAIL endif # provide specific link file ifeq (,$(wildcard $(TEST_DIR)/$(TEST).ld)) LINK = $(BUILD_DIR)/link.ld else LINK = $(TEST_DIR)/$(TEST).ld endif VPATH = $(TEST_DIR) $(BUILD_DIR) $(TBDIR) -include $(TEST_DIR)/$(TEST).mki # Testbench DPI sources TB_DPI_SRCS = jtagdpi/jtagdpi.c \ tcp_server/tcp_server.c TB_DPI_INCS := $(addprefix -I$(TBDIR)/,$(dir $(TB_DPI_SRCS))) # Add testbench include paths CFLAGS += $(TB_DPI_INCS) TB_DPI_SRCS := $(addprefix $(TBDIR)/,$(TB_DPI_SRCS)) # Testbench sources TB_VERILATOR_SRCS = $(TBDIR)/test_tb_top.cpp $(TB_DPI_SRCS) TBFILES = $(TBDIR)/tb_top_pkg.sv \ $(TBDIR)/tb_top.sv \ $(TBDIR)/ahb_sif.sv \ $(TBDIR)/jtagdpi/jtagdpi.sv \ $(TBDIR)/ahb_lite_2to1_mux.sv \ $(TBDIR)/ahb_lsu_dma_bridge.sv \ $(TBDIR)/axi4_mux/axi_crossbar_wrap_2x1.v \ $(TBDIR)/axi4_mux/arbiter.v \ $(TBDIR)/axi4_mux/axi_crossbar_addr.v \ $(TBDIR)/axi4_mux/axi_crossbar_rd.v \ $(TBDIR)/axi4_mux/axi_crossbar.v \ $(TBDIR)/axi4_mux/axi_crossbar_wr.v \ $(TBDIR)/axi4_mux/axi_register_rd.v \ $(TBDIR)/axi4_mux/axi_register_wr.v \ $(TBDIR)/axi4_mux/priority_encoder.v defines = $(BUILD_DIR)/common_defines.vh defines += ${RV_ROOT}/design/include/el2_def.sv defines += $(BUILD_DIR)/el2_pdef.vh includes = -I${BUILD_DIR} -I$(TBDIR)/axi4_mux CM_HIER_FILE = $(RV_ROOT)/cm.cfg # Verilator supports only C++14 and newer CFLAGS += -std=c++14 # Optimization for better performance; alternative is nothing for # slower runtime (faster compiles) -O2 for faster runtime (slower # compiles), or -O for balance. VERILATOR_MAKE_FLAGS = OPT_FAST="-Os" # Targets all: clean verilator clean: rm -rf *.log *.s *.hex *.dis *.tbl irun* vcs* simv* *.map snapshots \ verilator* *.exe obj* *.o *.sym ucli.key vc_hdrs.h csrc *.csv work \ dataset.asdb library.cfg vsimsa.cfg riviera-build wave.asdb ############ Model Builds ############################### # If define files do not exist, then run veer.config. ${BUILD_DIR}/defines.h: BUILD_PATH=${BUILD_DIR} ${RV_ROOT}/configs/veer.config -target=$(target) $(CONF_PARAMS) verilator-build: ${TBFILES} ${BUILD_DIR}/defines.h $(TB_VERILATOR_SRCS) $(VERILATOR) --cc -CFLAGS "${CFLAGS}" --coverage-max-width 20000 $(defines) \ $(includes) -I${RV_ROOT}/testbench -f ${RV_ROOT}/testbench/flist \ $(VERILATOR_SKIP_WARNINGS) $(VERILATOR_EXTRA_ARGS) ${TB_SILENT_FAIL} ${TBFILES} --top-module tb_top \ -exe $(TB_VERILATOR_SRCS) --autoflush --timing $(VERILATOR_DEBUG) $(VERILATOR_COVERAGE) -fno-table cp ${RV_ROOT}/testbench/test_tb_top.cpp obj_dir/ $(MAKE) -e -C obj_dir/ -f Vtb_top.mk $(VERILATOR_MAKE_FLAGS) touch verilator-build vcs-build: ${TBFILES} ${BUILD_DIR}/defines.h $(VCS) -full64 -assert svaext -sverilog +define+RV_OPENSOURCE $(ASSERT_DEFINES) \ +error+500 +incdir+${RV_ROOT}/design/lib \ +incdir+${RV_ROOT}/design/include ${BUILD_DIR}/common_defines.vh \ +incdir+$(BUILD_DIR) +libext+.v $(defines) -CFLAGS "${CFLAGS}" \ -cm_hier $(CM_HIER_FILE) \ -f ${RV_ROOT}/testbench/flist ${TBFILES} ${TB_DPI_SRCS} -l vcs.log touch vcs-build irun-build: ${TBFILES} ${BUILD_DIR}/defines.h $(IRUN) -64bit -elaborate $(IRUN_DEBUG) $(ASSERT_DEFINES) -q -sv -sysv -nowarn CUVIHR \ -xmlibdirpath . -xmlibdirname veer.build \ -incdir ${RV_ROOT}/design/lib -incdir ${RV_ROOT}/design/include \ -vlog_ext +.vh+.h $(defines) -incdir $(BUILD_DIR) \ -f ${RV_ROOT}/testbench/flist -top tb_top ${TBFILES} \ -I${RV_ROOT}/testbench -elaborate -snapshot ${snapshot} $(profile) touch irun-build riviera-build: ${TBFILES} ${BUILD_DIR}/defines.h vlib work vlog -work work ${ASSERT_DEFINES} \ +incdir+${RV_ROOT}/design/lib \ +incdir+${RV_ROOT}/design/include \ +incdir+${BUILD_DIR} \ -y ${RV_ROOT}/design/lib +libext+.v+.vh \ $(defines) \ -f ${RV_ROOT}/testbench/flist \ ${TBFILES} touch riviera-build ############ TEST Simulation ############################### verilator: program.hex verilator-build # FIXME: Assuming here that either begin_signature or end_signature implies # that both symbols are present. grep -E "(begin|end)_signature" $(TEST).sym >/dev/null 2>&1; \ if [ $$? -eq 0 ]; then \ BEG=`grep "begin_signature" $(TEST).sym | cut -d\ -f 1`;\ END=`grep "end_signature" $(TEST).sym | cut -d\ -f 1`;\ ./obj_dir/Vtb_top ${TB_EXTRA_ARGS} --mem-signature $${BEG} $${END}; \ else \ ./obj_dir/Vtb_top ${TB_EXTRA_ARGS}; \ fi irun: program.hex irun-build $(IRUN) -64bit -abvglobalfailurelimit 1 +lic_queue -licqueue \ -status -xmlibdirpath . -xmlibdirname veer.build \ -snapshot ${snapshot} -r $(snapshot) $(IRUN_DEBUG_RUN) $(profile) vcs: program.hex vcs-build ./simv $(DEBUG_PLUS) +vcs+lic+wait -l vcs.log vlog: program.hex ${TBFILES} ${BUILD_DIR}/defines.h $(VLOG) -l vlog.log -sv -mfcu +incdir+${BUILD_DIR}+${RV_ROOT}/design/include+${RV_ROOT}/design/lib -ccflags "${CFLAGS}"\ $(ASSERT_DEFINES) $(defines) -f ${RV_ROOT}/testbench/flist ${TBFILES} ${TB_DPI_SRCS} -R +nowarn3829 +nowarn2583 ${DEBUG_PLUS} -suppress 14408 -suppress 16154 riviera: program.hex riviera-build vsim -c -lib work ${DEBUG_PLUS} ${RIVIERA_DEBUG} tb_top -do "run -all; exit" -l riviera.log ############ TEST build ############################### picolibc: $(MAKE) -f ${RV_ROOT}/tools/picolibc.mk all ifeq ($(shell which $(GCC_PREFIX)-gcc 2> /dev/null),) program.hex: ${BUILD_DIR}/defines.h @echo " !!! No $(GCC_PREFIX)-gcc in path, using canned hex files !!" $(eval USER_MODE := $(if $(shell grep "define \+RV_USER_MODE \+1" ${BUILD_DIR}/defines.h),1,0)) stat ${HEX_DIR}/user_mode${USER_MODE}/$(TEST).hex >/dev/null 2>&1; \ if [ $$? -eq 0 ]; then \ cp ${HEX_DIR}/user_mode${USER_MODE}/$(TEST).hex program.hex; \ else \ echo "Canned hex not found: ${HEX_DIR}/user_mode${USER_MODE}/$(TEST).hex"; \ exit 1; \ fi else ifneq (,$(wildcard $(TEST_DIR)/$(TEST).makefile)) program.hex: picolibc @echo Building $(TEST) via $(TEST_DIR)/$(TEST).makefile $(MAKE) -f $(TEST_DIR)/$(TEST).makefile else program.hex: picolibc $(OFILES) ${BUILD_DIR}/defines.h @echo Building $(TEST) $(GCC_PREFIX)-gcc $(LD_ABI) --verbose -Wl,-Map=$(TEST).map -T$(LINK) --specs=$(PICOLIBC_DIR)/picolibc.specs $(TEST_LIBS) -nostartfiles $(OFILES) -o $(TEST).exe $(GCC_PREFIX)-objcopy -O verilog $(TEST).exe program.hex $(GCC_PREFIX)-objdump -S $(TEST).exe > $(TEST).dis $(GCC_PREFIX)-nm -B -n $(TEST).exe > $(TEST).sym @echo Completed building $(TEST) %.o : %.s ${BUILD_DIR}/defines.h $(GCC_PREFIX)-cpp -I${BUILD_DIR} $< > $*.cpp.s $(GCC_PREFIX)-as ${CC_ABI} $*.cpp.s -o $@ %.o : %.c picolibc ${BUILD_DIR}/defines.h $(GCC_PREFIX)-gcc ${includes} --specs=$(PICOLIBC_DIR)/picolibc.specs ${TEST_CFLAGS} -DCOMPILER_FLAGS="\"${TEST_CFLAGS}\"" ${CC_ABI} -c $< -o $@ endif endif help: @echo Make sure the environment variable RV_ROOT is set. @echo Possible targets: verilator vcs irun vlog riviera help clean all verilator-build irun-build vcs-build riviera-build program.hex .PHONY: help clean picolibc verilator vcs irun vlog riviera ================================================ FILE: tools/addassign ================================================ #!/usr/bin/perl use Getopt::Long; $helpusage = "placeholder"; GetOptions ('in=s' => \$in, 'prefix=s' => \$prefix) || die("$helpusage"); @in=`cat $in`; foreach $line (@in) { if ($line=~/\#/) { next; } if ($line=~/([^=]+)=/) { $sig=$1; $sig=~s/\s+//g; printf("logic $sig;\n"); } } foreach $line (@in) { if ($line=~/\#/) { next; } if ($line=~/([^=]+)=\s*;/) { printf("assign ${prefix}$1 = 1'b0;\n"); next; } if ($line=~/([^=]+)=\s*\(\s*\);/) { printf("assign ${prefix}$1 = 1'b0;\n"); next; } if ($line =~ /=/) { printf("assign ${prefix}$line"); } else { printf("$line"); } } exit; ================================================ FILE: tools/coredecode ================================================ #!/usr/bin/perl use Getopt::Long; $helpusage = "placeholder"; GetOptions ('legal' => \$legal, 'in=s' => \$in, 'out=s' => \$out, 'view=s' => \$view ) || die("$helpusage"); if (!defined($in)) { die("must define -in=input"); } if (!defined($out)) { $out="${in}.out"; } if ($in eq "decode") { $view="rv32i"; } elsif ($in eq "cdecode") { $view="rv32c"; } elsif (rindex($in,"csrdecode",0) == 0) { $view="csr"; } if (defined($in)) { printf("in=$in\n"); } if (defined($out)) { printf("out=$out\n"); } if (defined($view)) { printf("view=$view\n"); } @in=`cat $in`; $gather=0; $TIMEOUT=50; foreach $line (@in) { #printf("$pstate: $line"); if ($line=~/^\s*\#/) { #printf("skip $line"); next; } if ($gather==1) { if ($line=~/(\S+)/) { if ($line=~/}/) { $gather=0; $position=0; next; } $label=$1; $label=~s/,//g; if ($pstate==2) { if (defined($INPUT{$CVIEW}{$label})) { die("input $label already defined"); } $INPUT{$CVIEW}{$label}=$position++; $INPUTLEN{$CVIEW}++; $INPUTSTR{$CVIEW}.=" $label"; } elsif ($pstate==3) { if (defined($OUTPUT{$CVIEW}{$label})) { die("output $label already defined"); } $OUTPUT{$CVIEW}{$label}=$position++; $OUTPUTLEN{$CVIEW}++; $OUTPUTSTR{$CVIEW}.=" $label"; } else { die("unknown pstate $pstate in gather"); } } } if ($line=~/^.definition/) { $pstate=1; next; } if ($pstate==1) { # definition if ($line!~/^.output/) { if ($line=~/(\S+)\s*=\s*(\S+)/) { $key=$1; $value=$2; $value=~s/\./-/g; $value=~s/\[//g; $value=~s/\]//g; $DEFINITION{$key}=$value; } } else { $pstate=2; next; } } if ($line=~/^.input/) { $pstate=2; next; } if ($pstate==2) { # input if ($line=~/(\S+)\s*=\s*\{/) { $CVIEW=$1; $gather=1; next; } } if ($line=~/^.output/) { $pstate=3; next; } if ($pstate==3) { # output if ($line=~/(\S+)\s*=\s*\{/) { $CVIEW=$1; $gather=1; next; } } if ($line=~/^.decode/) { $pstate=4; next; } if ($pstate==4) { # decode if ($line=~/([^\[]+)\[([^\]]+)\]\s*=\s*\{([^\}]+)\}/) { $dview=$1; $inst=$2; $body=$3; $dview=~s/\s+//g; $inst=~s/\s+//g; #printf("$dview $inst $body\n"); if ($inst=~/([^\{]+)\{([^-]+)-([^\}]+)\}/) { $base=$1; $lo=$2; $hi=$3; $hi++; for ($i=0; $i<$TIMEOUT && $lo ne $hi; $i++) { #printf("decode $dview $base$lo\n"); $expand=$base.$lo; if (!defined($DEFINITION{$expand})) { die("could not find instruction definition for inst $expand"); } $DECODE{$dview}{$expand}=$body; $lo++; } if ($i == $TIMEOUT) { die("timeout in decode expansion"); } } else { if (!defined($DEFINITION{$inst})) { die("could not find instruction definition for inst $inst"); } $DECODE{$dview}{$inst}=$body; } } } } #printf("view $view len %d\n",$OUTPUTLEN{$view}); #printf("$OUTPUTSTR{$view}\n"); # need to switch this somehow based on 16/32 printf(".i %d\n",$INPUTLEN{$view}); if (defined($legal)) { printf(".o 1\n"); } else { printf(".o %d\n",$OUTPUTLEN{$view}); } printf(".ilb %s\n",$INPUTSTR{$view}); if (defined($legal)) { printf(".ob legal\n"); } else { printf(".ob %s\n",$OUTPUTSTR{$view}); } if (defined($legal)) { printf(".type fd\n"); } else { printf(".type fr\n"); } $DEFAULT_TEMPLATE='0'x$OUTPUTLEN{$view}; foreach $inst (sort keys %{ $DECODE{$view} }) { $body=$DECODE{$view}{$inst}; @sigs=split(' ',$body); $template=$DEFAULT_TEMPLATE; foreach $sig (@sigs) { if (!defined($OUTPUT{$view}{$sig})) { die("could not find output definition for sig $sig in view $view"); } $position=$OUTPUT{$view}{$sig}; substr($template,$position,1,1); } # if (!defined($DEFINITION{$inst})) { die("could not find instruction defintion for inst $inst"); } printf("# $inst\n"); if (defined($legal)) { printf("$DEFINITION{$inst} 1\n"); } else { printf("$DEFINITION{$inst} $template\n"); } } exit; foreach $inst (sort keys %DEFINITION) { $value=$DEFINITION{$inst}; printf("%-10s = $value\n",$inst); } foreach $sig (sort keys %{ $OUTPUT{$view} }) { $position=$OUTPUT{$view}{$sig}; printf("$sig $position\n"); } ================================================ FILE: tools/hex_canned_update.sh ================================================ #!/bin/bash # Expected usage: # export RV_ROOT=/path/to/cores-veer-el2 # bash tools/hex_canned_update.sh if [[ -z "$RV_ROOT" ]]; then echo "RV_ROOT is not set" 1>&2 exit 1 fi ASM=($(find $RV_ROOT/testbench/asm -maxdepth 1 -regex ".*\.\(s\|mki\)" -printf "%f\n" | sed 's/\.\(s\|mki\)$//' | grep -vE "(common|crt0)")) CT=($(find $RV_ROOT/testbench/tests -mindepth 1 -type d -printf "%f\n")) TESTS=("${ASM[@]}" "${CT[@]}") echo "Detected tests:" echo "---------------" echo "${TESTS[@]}" echo "---------------" USER_MODES=("0" "1") MAKE_CMD="make -f $RV_ROOT/tools/Makefile" HEX_DIR=testbench/hex # Clear old hex files rm -rdf $HEX_DIR/* PARAMS="" for umode in ${USER_MODES[@]}; do mkdir -p $HEX_DIR/user_mode$umode for test in ${TESTS[@]}; do if [[ "$umode" == "1" ]]; then PARAMS="-set=user_mode=1 -set=smepmp=1 $PARAMS" # csr_mseccfg test is only available in user mode elif [[ "$test" == "csr_mseccfg" ]]; then continue fi $MAKE_CMD clean >/dev/null $MAKE_CMD program.hex CONF_PARAMS="$PARAMS" TEST=$test >/dev/null HEX_PATH="$HEX_DIR/user_mode$umode/$test.hex" echo "TEST = " $test if [ -f "program.hex" ]; then echo "Copying $test:program.hex to ["$HEX_PATH"]" cp program.hex $HEX_PATH else echo "program.hex not found. Possible build error." exit 1 fi done done exit 0 ================================================ FILE: tools/picmap ================================================ #!/usr/bin/perl use Getopt::Long; use integer; $helpusage = "placeholder"; GetOptions ('total_int=s' => \$total_int)|| die("$helpusage"); $LEN=15; #printf("logic [2:0] mask;\n"); printf("// mask[3:0] = { 4'b1000 - 30b mask,4'b0100 - 31b mask, 4'b0010 - 28b mask, 4'b0001 - 32b mask }\n"); printf("always_comb begin\n"); printf(" case \(address[14:0]\)\n"); printf(" 15'b011000000000000 : mask[3:0] = 4'b0100;\n"); for ($i=1; $i<=$total_int; $i++) { $j=hex("4000"); printf(" 15'b%s : mask[3:0] = 4'b1000;\n",d2b($j+$i*4)); } for ($i=1; $i<=$total_int; $i++) { $j=hex("2000"); printf(" 15'b%s : mask[3:0] = 4'b0100;\n",d2b($j+$i*4)); } for ($i=1; $i<=$total_int; $i++) { $j=hex("0"); printf(" 15'b%s : mask[3:0] = 4'b0010;\n",d2b($j+$i*4)); } printf(" %-17s : mask[3:0] = 4'b0001;\n","default"); printf(" endcase\n"); printf("end\n"); sub b2d { my ($v) = @_; $v = oct("0b" . $v); return($v); } sub d2b { my ($v) = @_; my $repeat; $v = sprintf "%b",$v; if (length($v)<$LEN) { $repeat=$LEN-length($v); $v="0"x$repeat.$v; } elsif (length($v)>$LEN) { $v=substr($v,length($v)-$LEN,$LEN); } return($v); } ================================================ FILE: tools/picolibc.mk ================================================ GCC_PREFIX ?= riscv64-unknown-elf MAKEFILE_PATH = $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) PICOLIBC_PATH = $(abspath $(MAKEFILE_PATH)/../third_party/picolibc) BUILD_PATH = $(PICOLIBC_PATH)/build INSTALL_PATH = $(PICOLIBC_PATH)/install ifeq ($(CCACHE), ) MESON_CROSS_CC = '$(GCC_PREFIX)-gcc' else MESON_CROSS_CC = ['$(CCACHE)', '$(GCC_PREFIX)-gcc'] endif define CROSSFILE [binaries] c = $(MESON_CROSS_CC) ar = '$(GCC_PREFIX)-gcc-ar' as = '$(GCC_PREFIX)-as' nm = '$(GCC_PREFIX)-gcc-nm' strip = '$(GCC_PREFIX)-strip' [host_machine] system = 'unknown' cpu_family = 'riscv64' cpu = 'riscv' endian = 'little' [properties] # this uses shorter but slower function entry code c_args = [ '-msave-restore' ] # default multilib is 64 bit c_args_ = [ '-mcmodel=medany' ] endef export CROSSFILE $(BUILD_PATH): mkdir -p $@ $(BUILD_PATH)/cross.txt: | $(BUILD_PATH) @echo "$$CROSSFILE" > $@ $(INSTALL_PATH)/picolibc.specs: $(BUILD_PATH)/cross.txt | $(BUILD_PATH) cd $(PICOLIBC_PATH) && meson $(BUILD_PATH) \ -Dmultilib=true \ -Dmultilib-list=rv32imac/ilp32 \ -Dpicocrt=false \ -Datomic-ungetc=false \ -Dthread-local-storage=false \ -Dio-long-long=true \ -Dformat-default=integer \ -Dincludedir=picolibc/$(GCC_PREFIX)/include \ -Dlibdir=picolibc/$(GCC_PREFIX)/lib \ -Dprefix=$(INSTALL_PATH) \ -Dspecsdir=$(INSTALL_PATH) \ --cross-file $(BUILD_PATH)/cross.txt cd $(BUILD_PATH) && meson install all: $(INSTALL_PATH)/picolibc.specs clean: rm -rf $(BUILD_PATH) .PHONY: all clean ================================================ FILE: tools/prefix_macros.sh ================================================ # !/bin/bash # Set flag to exit the script on first error set -e # Check if RV_ROOT is set if [ -z "$RV_ROOT" ]; then echo "Error: RV_ROOT is not set." exit 1 fi # Prefix that will be added to all required macro/struct/module names PREFIX="${PREFIX:-veer0_}" # Path to directory where common_defines.vh, el2_param.vh, el2_pdef.vh and pd_defines.vh reside DEFINES_PATH="${DEFINES_PATH:-${RV_ROOT}/snapshots/default}" # Path to directory hierarchy where RTL sources reside DESIGN_DIR="${DESIGN_DIR:-${RV_ROOT}/design}" COMMON_DEFINES="$DEFINES_PATH/common_defines.vh" EL2_PARAM="$DEFINES_PATH/el2_param.vh" EL2_PDEF="$DEFINES_PATH/el2_pdef.vh" PD_DEFINES="$DEFINES_PATH/pd_defines.vh" EL2_DEF="$DESIGN_DIR/include/el2_def.sv" EL2_IFU_IC_MEM="$DESIGN_DIR/ifu/el2_ifu_ic_mem.sv" echo "Starting script with following settings:" echo "PREFIX=$PREFIX" echo "DEFINES_PATH=$DEFINES_PATH" echo -e "DESIGN_DIR=$DESIGN_DIR\n" # Define regex patterns for matching defines DEFINES_REGEX="s/((\`define)|(\`ifndef)|(\`undef)) ([A-Z0-9_]+).*/\5/p" DEFINES_REPLACE_REGEX="s/((\`define)|(\`ifndef)|(\`undef)) ([A-Z0-9_]+)/\1 "$PREFIX"\5/" STRUCT_REPLACE_REGEX="s/el2_param_t/"$PREFIX"el2_param_t/g" MODULES_REGEX="s/^module ([\`A-Za-z0-9_]+).*/\1/p" # Extract unique defines from all sources DEFINES="$(sed -nr "$DEFINES_REGEX" $COMMON_DEFINES $PD_DEFINES $EL2_IFU_IC_MEM | sort -ur)" # Skip files that should not be processed SKIP_DESIGN_FILES="el2_param.vh\|el2_pdef.vh\|common_defines.vh\|pd_defines.vh" DESIGN_FILES="$(find $DESIGN_DIR -name "*.sv" -o -name "*.vh" -o -name "*.v" | grep -v $SKIP_DESIGN_FILES)" DESIGN_FILES+=" $EXTRA_DESIGN_FILES" MODULES="$(sed -nr "$MODULES_REGEX" $DESIGN_FILES | sort -ur)" if [ "${DEBUG}" = "1" ]; then echo "DEBUG: DEFINES_REGEX=$DEFINES_REGEX" echo "DEBUG: DEFINES_REPLACE_REGEX=$DEFINES_REPLACE_REGEX" echo "DEBUG: STRUCT_REPLACE_REGEX=$STRUCT_REPLACE_REGEX" echo "DEBUG: MODULES_REGEX=$MODULES_REGEX" echo echo "DEBUG: DEFINES=$DEFINES" echo "DEBUG: DESIGN_FILES=$DESIGN_FILES" echo "DEBUG: MODULES=$MODULES" echo fi # Add prefix to macro names OUTPUT_COMMON_DEFINES=$DEFINES_PATH/"$PREFIX"common_defines.vh OUTPUT_PD_DEFINES=$DEFINES_PATH/"$PREFIX"pd_defines.vh echo "Adding prefix to macro names in $OUTPUT_COMMON_DEFINES and $OUTPUT_PD_DEFINES" sed -E "$DEFINES_REPLACE_REGEX" $COMMON_DEFINES >$OUTPUT_COMMON_DEFINES sed -E "$DEFINES_REPLACE_REGEX" $PD_DEFINES >$OUTPUT_PD_DEFINES # Add prefix to RV_RCG macros RV_RCG_REPLACE_REGEX="s/^(\`define "${PREFIX}"\w+_RV_ICG )(\w+)/\1"${PREFIX}"\2/g" sed -i -E "$RV_RCG_REPLACE_REGEX" $OUTPUT_COMMON_DEFINES # Add prefix to VeeR config struct OUTPUT_EL2_PARAM=$DEFINES_PATH/"$PREFIX"el2_param.vh OUTPUT_EL2_PDEF=$DEFINES_PATH/"$PREFIX"el2_pdef.vh echo "Adding prefix to VeeR config struct in $OUTPUT_EL2_PARAM and $OUTPUT_EL2_PDEF" sed "$STRUCT_REPLACE_REGEX" "$EL2_PARAM" >$OUTPUT_EL2_PARAM sed "$STRUCT_REPLACE_REGEX" "$EL2_PDEF" >$OUTPUT_EL2_PDEF sed -i "$STRUCT_REPLACE_REGEX" $DESIGN_FILES # Replace renamed macros in RTL sources echo "Replacing renamed macros in RTL sources" for DEFINE in $DEFINES; do sed -i "s/\`$DEFINE/\`"$PREFIX"$DEFINE/g" $DESIGN_FILES sed -i -E "s/((\`ifdef)|(\`ifndef)) $DEFINE/\1 "$PREFIX"$DEFINE/g" $DESIGN_FILES done # Replace include names in RTL sources echo "Replacing include names in RTL sources" sed -i "s/include \"el2_param.vh\"/include \""$PREFIX"el2_param.vh\"/g" $DESIGN_FILES sed -i "s/include \"el2_pdef.vh\"/include \""$PREFIX"el2_pdef.vh\"/g" $DESIGN_FILES sed -i "s/include \"common_defines.vh\"/include \""$PREFIX"common_defines.vh\"/g" $OUTPUT_PD_DEFINES # Replace package name and its imports in RTL sources echo "Replacing package name and its imports in RTL sources" sed -i "s/import el2_pkg/import "$PREFIX"el2_pkg/g" $DESIGN_FILES sed -i "s/package el2_pkg/package "$PREFIX"el2_pkg/g" $EL2_DEF # Add prefix to all module names echo "Adding prefix to all module names" perl -pi -e "s/module \`?(?!${PREFIX})([A-Za-z0-9_]+)/module ${PREFIX}\1/g" $DESIGN_FILES # Add prefix to all module instantiations echo "Adding prefix to all module instantiations" for MODULE in $MODULES; do # Exclude the prefix from the MODULE name if it already contains the prefix MODULE=$(echo $MODULE | perl -pe "s/${PREFIX}//") echo "Processing MODULE=$MODULE" perl -pi -e "s/(^|[^A-Za-z0-9_])(?/tests/requirements.txt ``` 1. For your shell run (assuming that Renode is in your system's `PATH`): ```shell renode-test veer.robot ``` ## Directory structure * [veer.resc](veer.resc) - Renode script defining the simulation environment * [veer.repl](veer.repl) - Renode platform description used in user mode tests * [veer.robot](veer.robot) - [Robot Framework](https://robotframework.org/) test file, listing all test cases to be run in Renode * [build-all-tests.sh](build-all-tests.sh) - Shell script used for building test binaries * [run-tests.sh](run-tests.sh) - Shell script used to simplify executing user mode tests. ================================================ FILE: tools/renode/build-all-tests.sh ================================================ #!/usr/bin/env bash set -x set -e test_dir=${RV_ROOT}/testbench/tests/ tests="csr_access csr_misa csr_mstatus dhry insns irq modesw perf_counters pmp" mkdir -p build cd build for test in ${tests}; do test_name=$(basename ${test}) make CFLAGS=-DUSE_HTIF=false -f ${RV_ROOT}/tools/Makefile TEST=${test_name} USER_MODE=1 program.hex mv ${test_name}.exe ../${test_name}.elf make -f ${RV_ROOT}/tools/Makefile clean done cd - ================================================ FILE: tools/renode/veer.repl ================================================ mem: Memory.MappedMemory @sysbus 0x80000000 size: 0x10000000 htif_mem: Memory.MappedMemory @sysbus 0xD0580000 size: 0x1000 cpu: CPU.VeeR_EL2 @ sysbus hartId: 0 dhry_mem: Memory.MappedMemory @sysbus 0xF0040000 size: 0x10000 ================================================ FILE: tools/renode/veer.resc ================================================ :name: VeeR $name?="VeeR" # Set to path of the ELF program to run $bin?=$ORIGIN/csr_access.elf using sysbus mach create $name $platform?=$ORIGIN/veer.repl machine LoadPlatformDescription $platform macro reset """ sysbus LoadELF $bin """ runMacro $reset machine CreateVirtualConsole "htif" python """ from Antmicro.Renode.Peripherals.Bus import Access, SysbusAccessWidth htif = monitor.Machine["sysbus.htif"] bus = monitor.Machine.SystemBus def store_char(_, __, ___, value): if(value not in (0x1, 0xFF) and value < 0xFF): htif.DisplayChar(value) else: for x in [ord(c) for c in "\nFinished: " + ("FAILED\n" if value == 0x1 else "PASSED\n")]: htif.DisplayChar(x) htif.DebugLog("TEST FINISHED") monitor.Machine.Pause() bus.AddWatchpointHook(bus.GetSymbolAddress("tohost"), SysbusAccessWidth.DoubleWord, Access.Write, store_char) bus.AddWatchpointHook(bus.GetSymbolAddress("tohost"), SysbusAccessWidth.Byte, Access.Write, store_char) """ cpu WfiAsNop true showAnalyzer htif ================================================ FILE: tools/renode/veer.robot ================================================ *** Keywords *** Prepare Machine [Arguments] ${bin} Execute Command $bin=@${bin} Execute Command i @${CURDIR}/veer.resc Create Terminal Tester sysbus.htif timeout=0 defaultMatchNextLine=true Create Log Tester 1 Execute Command logLevel 0 sysbus.htif Wait For Log Entry TEST FINISHED level=Debug Wait For Regex [Arguments] ${pattern} Wait For Line On Uart ${pattern} treatAsRegex=true Wait For OK Message [Arguments] ${pattern} Wait For Regex \\[\\s+OK\\s+\\] ${pattern} Check CSR Access [Arguments] ${pattern} ${expect_trap}=${False} IF ${expect_trap} Wait For Line On Uart trap! mstatus=0x00000000, mcause=0x00000002 END Wait For OK Message ${pattern} *** Test Cases *** Should Have All CSRs # We are testing SMEPMP registers here, so make sure the extension is active (mseccfg, mseccfgh) Execute Command $platform=@${CURDIR}/veer_smepmp.repl Prepare Machine ${CURDIR}/csr_access.elf Wait For Line On Uart ${EMPTY} Wait For Line On Uart Hello VeeR Wait For Line On Uart Testing CSR read... Check CSR Access 0xF11 'mvendorid' Check CSR Access 0xF12 'marchid' Check CSR Access 0xF13 'mimpid' Check CSR Access 0xF14 'mhartid' Check CSR Access 0x300 'mstatus' Check CSR Access 0x301 'misa' Check CSR Access 0x304 'mie' Check CSR Access 0x305 'mtvec' Check CSR Access 0x306 'mcounteren' Check CSR Access 0x320 'mcountinhibit' Check CSR Access 0x340 'mscratch' Check CSR Access 0x341 'mepc' Check CSR Access 0x342 'mcause' Check CSR Access 0x343 'mtval' Check CSR Access 0x344 'mip' Check CSR Access 0xB00 'mcycle' Check CSR Access 0xB02 'minstret' Check CSR Access 0xB80 'mcycleh' Check CSR Access 0xB82 'minstreth' Check CSR Access 0x30A 'menvcfg' Check CSR Access 0x31A 'menvcfgh' Check CSR Access 0x747 'mseccfg' Check CSR Access 0x757 'mseccfgh' Check CSR Access 0x3A0 'pmpcfg0' Check CSR Access 0x3B0 'pmpaddr0' Check CSR Access 0x3C0 'pmpaddr16' Check CSR Access 0x3D0 'pmpaddr32' Check CSR Access 0x3E0 'pmpaddr48' Check CSR Access 0xC00 'cycle' Check CSR Access 0xC80 'cycleh' Check CSR Access 0xC02 'instret' Check CSR Access 0xC82 'instreth' Check CSR Access 0x7FF 'mscause' Check CSR Access 0xBC0 'mdeau' Check CSR Access 0xFC0 'mdseac' Check CSR Access 0xBC8 'meivt' Check CSR Access 0xFC8 'meihap' Check CSR Access 0xBC9 'meipt' Check CSR Access 0xBCC 'meicurpl' Check CSR Access 0xBCB 'meicidpl' Check CSR Access 0x7A0 'mtsel' Check CSR Access 0x7A1 'mtdata1' Check CSR Access 0x7A2 'mtdata2' Check CSR Access 0x7C0 'mrac' Check CSR Access 0xB03 'mhpmc3' Check CSR Access 0xB04 'mhpmc4' Check CSR Access 0xB05 'mhpmc5' Check CSR Access 0xB06 'mhpmc6' Check CSR Access 0xB83 'mhpmc3h' Check CSR Access 0xB84 'mhpmc4h' Check CSR Access 0xB85 'mhpmc5h' Check CSR Access 0xB86 'mhpmc6h' Check CSR Access 0x323 'mhpme3' Check CSR Access 0x324 'mhpme4' Check CSR Access 0x325 'mhpme5' Check CSR Access 0x326 'mhpme6' Check CSR Access 0x7F0 'micect' Check CSR Access 0x7F1 'miccmect' Check CSR Access 0x7F2 'mdccmect' Check CSR Access 0x7C6 'mpmc' Check CSR Access 0x7F8 'mcgc' Check CSR Access 0x7C2 'mcpc' Check CSR Access 0x7F9 'mfdc' Check CSR Access 0x7D4 'mitctl0' Check CSR Access 0x7D7 'mitctl1' Check CSR Access 0x7D3 'mitb0' Check CSR Access 0x7D6 'mitb1' Check CSR Access 0x7D2 'mitcnt0' Check CSR Access 0x7D5 'mitcnt1' Check CSR Access 0xB07 'perfva' Check CSR Access 0xB08 'perfvb' Check CSR Access 0xB10 'perfvc' Check CSR Access 0xB87 'perfvd' Check CSR Access 0xB88 'perfve' Check CSR Access 0xB90 'perfvf' Check CSR Access 0x327 'perfvg' Check CSR Access 0x328 'perfvh' Check CSR Access 0x330 'perfvi' Check CSR Access 0x7CE 'mfdht' Check CSR Access 0x7CF 'mfdhs' Wait For Line On Uart Testing CSR write... Check CSR Access 0x304 'mie' Check CSR Access 0x340 'mscratch' Check CSR Access 0x30A 'menvcfg' Check CSR Access 0x31A 'menvcfgh' Wait For Line On Uart ${EMPTY} Wait For Line On Uart Hello from user_main() Wait For Line On Uart Testing CSR read... Check CSR Access 0xF11 'mvendorid' expect_trap=${True} Check CSR Access 0xF12 'marchid' expect_trap=${True} Check CSR Access 0xF13 'mimpid' expect_trap=${True} Check CSR Access 0xF14 'mhartid' expect_trap=${True} Check CSR Access 0x300 'mstatus' expect_trap=${True} Check CSR Access 0x301 'misa' expect_trap=${True} Check CSR Access 0x304 'mie' expect_trap=${True} Check CSR Access 0x305 'mtvec' expect_trap=${True} Check CSR Access 0x306 'mcounteren' expect_trap=${True} Check CSR Access 0x320 'mcountinhibit' expect_trap=${True} Check CSR Access 0x340 'mscratch' expect_trap=${True} Check CSR Access 0x341 'mepc' expect_trap=${True} Check CSR Access 0x342 'mcause' expect_trap=${True} Check CSR Access 0x343 'mtval' expect_trap=${True} Check CSR Access 0x344 'mip' expect_trap=${True} Check CSR Access 0xB00 'mcycle' expect_trap=${True} Check CSR Access 0xB02 'minstret' expect_trap=${True} Check CSR Access 0xB80 'mcycleh' expect_trap=${True} Check CSR Access 0xB82 'minstreth' expect_trap=${True} Check CSR Access 0x30A 'menvcfg' expect_trap=${True} Check CSR Access 0x31A 'menvcfgh' expect_trap=${True} Check CSR Access 0x747 'mseccfg' expect_trap=${True} Check CSR Access 0x757 'mseccfgh' expect_trap=${True} Check CSR Access 0x3A0 'pmpcfg0' expect_trap=${True} Check CSR Access 0x3B0 'pmpaddr0' expect_trap=${True} Check CSR Access 0x3C0 'pmpaddr16' expect_trap=${True} Check CSR Access 0x3D0 'pmpaddr32' expect_trap=${True} Check CSR Access 0x3E0 'pmpaddr48' expect_trap=${True} Check CSR Access 0xC00 'cycle' Check CSR Access 0xC80 'cycleh' Check CSR Access 0xC02 'instret' Check CSR Access 0xC82 'instreth' Check CSR Access 0x7FF 'mscause' expect_trap=${True} Check CSR Access 0xBC0 'mdeau' expect_trap=${True} Check CSR Access 0xFC0 'mdseac' expect_trap=${True} Check CSR Access 0xBC8 'meivt' expect_trap=${True} Check CSR Access 0xFC8 'meihap' expect_trap=${True} Check CSR Access 0xBC9 'meipt' expect_trap=${True} Check CSR Access 0xBCC 'meicurpl' expect_trap=${True} Check CSR Access 0xBCB 'meicidpl' expect_trap=${True} Check CSR Access 0x7A0 'mtsel' expect_trap=${True} Check CSR Access 0x7A1 'mtdata1' expect_trap=${True} Check CSR Access 0x7A2 'mtdata2' expect_trap=${True} Check CSR Access 0x7C0 'mrac' expect_trap=${True} Check CSR Access 0xB03 'mhpmc3' expect_trap=${True} Check CSR Access 0xB04 'mhpmc4' expect_trap=${True} Check CSR Access 0xB05 'mhpmc5' expect_trap=${True} Check CSR Access 0xB06 'mhpmc6' expect_trap=${True} Check CSR Access 0xB83 'mhpmc3h' expect_trap=${True} Check CSR Access 0xB84 'mhpmc4h' expect_trap=${True} Check CSR Access 0xB85 'mhpmc5h' expect_trap=${True} Check CSR Access 0xB86 'mhpmc6h' expect_trap=${True} Check CSR Access 0x323 'mhpme3' expect_trap=${True} Check CSR Access 0x324 'mhpme4' expect_trap=${True} Check CSR Access 0x325 'mhpme5' expect_trap=${True} Check CSR Access 0x326 'mhpme6' expect_trap=${True} Check CSR Access 0x7F0 'micect' expect_trap=${True} Check CSR Access 0x7F1 'miccmect' expect_trap=${True} Check CSR Access 0x7F2 'mdccmect' expect_trap=${True} Check CSR Access 0x7C6 'mpmc' expect_trap=${True} Check CSR Access 0x7F8 'mcgc' expect_trap=${True} Check CSR Access 0x7C2 'mcpc' expect_trap=${True} Check CSR Access 0x7F9 'mfdc' expect_trap=${True} Check CSR Access 0x7D4 'mitctl0' expect_trap=${True} Check CSR Access 0x7D7 'mitctl1' expect_trap=${True} Check CSR Access 0x7D3 'mitb0' expect_trap=${True} Check CSR Access 0x7D6 'mitb1' expect_trap=${True} Check CSR Access 0x7D2 'mitcnt0' expect_trap=${True} Check CSR Access 0x7D5 'mitcnt1' expect_trap=${True} Check CSR Access 0xB07 'perfva' expect_trap=${True} Check CSR Access 0xB08 'perfvb' expect_trap=${True} Check CSR Access 0xB10 'perfvc' expect_trap=${True} Check CSR Access 0xB87 'perfvd' expect_trap=${True} Check CSR Access 0xB88 'perfve' expect_trap=${True} Check CSR Access 0xB90 'perfvf' expect_trap=${True} Check CSR Access 0x327 'perfvg' expect_trap=${True} Check CSR Access 0x328 'perfvh' expect_trap=${True} Check CSR Access 0x330 'perfvi' expect_trap=${True} Check CSR Access 0x7CE 'mfdht' expect_trap=${True} Check CSR Access 0x7CF 'mfdhs' expect_trap=${True} Wait For Line On Uart Testing CSR write... Check CSR Access 0x304 'mie' expect_trap=${True} Check CSR Access 0x340 'mscratch' expect_trap=${True} Check CSR Access 0x30A 'menvcfg' expect_trap=${True} Check CSR Access 0x31A 'menvcfgh' expect_trap=${True} Wait For Line On Uart Attempting to write mscratch... Wait For Line On Uart trap! mstatus=0x00000000, mcause=0x00000002 Wait For Line On Uart trap! mstatus=0x00000000, mcause=0x00000008 Wait For Line On Uart ${EMPTY} Wait For Line On Uart Hello from machine_main() Wait For Line On Uart Reading mscratch... Wait For Regex \\[\\s+OK\\s+\\] Wait For Line On Uart Finished: PASSED matchNextLine=false Should Have Correct MStatus Prepare Machine ${CURDIR}/csr_mstatus.elf Wait For Line On Uart M mode: Wait For Line On Uart 0x1800 Wait For Line On Uart 0x1800 Wait For Line On Uart ok. Wait For Line On Uart S mode: Wait For Line On Uart 0x800 Wait For Line On Uart 0x1800 Wait For Line On Uart not supported. Wait For Line On Uart U mode: Wait For Line On Uart 0x0 Wait For Line On Uart 0x0 Wait For Line On Uart ok. Wait For Line On Uart MPRV Wait For Line On Uart 0x20000 Wait For Line On Uart 0x20000 Wait For Line On Uart ok. Wait For Line On Uart 0x0 Wait For Line On Uart 0x0 Wait For Line On Uart ok. Wait For Line On Uart Finished: PASSED matchNextLine=false Should Have Correct MISA Prepare Machine ${CURDIR}/csr_misa.elf Wait For Line On Uart misa = 0x40101104 vs. 0x40101104 Wait For Line On Uart Finished: PASSED matchNextLine=false Should Pass Dhrystone Benchmark Prepare Machine ${CURDIR}/dhry.elf Wait For Line On Uart Finished: PASSED matchNextLine=false Should Implement Insn Prepare Machine ${CURDIR}/insns.elf Wait For Line On Uart Hello VeeR Wait For Line On Uart testing EBREAK Wait For Line On Uart trap! mstatus=0x1800, mcause=0x3, mepc=0x800002f6, insn=0x19002 Wait For Line On Uart pass Wait For Line On Uart testing ECALL Wait For Line On Uart trap! mstatus=0x1800, mcause=0xb, mepc=0x80000332, insn=0x73 Wait For Line On Uart pass Wait For Line On Uart testing WFI Wait For Line On Uart pass Wait For Line On Uart testing SRET Wait For Line On Uart trap! mstatus=0x1800, mcause=0x2, mepc=0x80000378, insn=0x10200073 Wait For Line On Uart pass Wait For Line On Uart Hello from user_main() Wait For Line On Uart testing EBREAK Wait For Line On Uart trap! mstatus=0x80, mcause=0x3, mepc=0x8000010c, insn=0x19002 Wait For Line On Uart pass Wait For Line On Uart testing ECALL Wait For Line On Uart trap! mstatus=0x80, mcause=0x8, mepc=0x8000014c, insn=0x73 Wait For Line On Uart pass Wait For Line On Uart testing WFI Wait For Line On Uart pass Wait For Line On Uart testing SRET Wait For Line On Uart trap! mstatus=0x80, mcause=0x2, mepc=0x80000196, insn=0x10200073 Wait For Line On Uart pass Wait For Line On Uart testing MRET Wait For Line On Uart trap! mstatus=0x80, mcause=0x2, mepc=0x800001c4, insn=0x30200073 Wait For Line On Uart pass Wait For Line On Uart Finished: PASSED matchNextLine=false Should Correctly Implement Mode Switch Prepare machine ${CURDIR}/modesw.elf Wait For Line On Uart Hello VeeR Wait For OK Message MPRV cleared Wait For OK Message MPP is 11 Wait For Line On Uart doing ECALL (MPRV=0)... Wait For Line On Uart trap! mstatus=0x1800, mcause=0xb, mepc=0x80000136 Wait For Line On Uart Hello ECALL.M Wait For OK Message MPRV cleared Wait For OK Message MPP is 00 Wait For Line On Uart doing ECALL (MPRV=1) Wait For Line On Uart trap! mstatus=0x21800, mcause=0xb, mepc=0x80000136 Wait For Line On Uart Hello ECALL.M Wait For OK Message MPRV is set Wait For OK Message MPP is 00 Wait For Line On Uart Hello from user_main() Wait For Line On Uart doing ECALL... Wait For Line On Uart trap! mstatus=0x80, mcause=0x8, mepc=0x80000136 Wait For Line On Uart Hello ECALL.U Wait For Line On Uart clearing mstatus.MPRV Wait For OK Message MPP is 00 Wait For Line On Uart doing ECALL... Wait For Line On Uart trap! mstatus=0x80, mcause=0x8, mepc=0x80000136 Wait For Line On Uart Hello ECALL.U Wait For OK Message MPRV was cleared Wait For Line On Uart doing ECALL... Wait For Line On Uart trap! mstatus=0x80, mcause=0x8, mepc=0x80000136 Wait For Line On Uart Hello ECALL.U Wait For Line On Uart setting mstatus.MPRV Wait For OK Message MPP is 00 Wait For Line On Uart doing ECALL... Wait For Line On Uart trap! mstatus=0x80, mcause=0x8, mepc=0x80000136 Wait For Line On Uart Hello ECALL.U Wait For OK Message MPRV was cleared Wait For Line On Uart traps taken: Wait For Line On Uart 0. mcause=0xb mstatus=0x1800 Wait For Line On Uart 1. mcause=0xb mstatus=0x21800 Wait For Line On Uart 2. mcause=0x8 mstatus=0x80 Wait For Line On Uart 3. mcause=0x8 mstatus=0x80 Wait For Line On Uart 4. mcause=0x8 mstatus=0x80 Wait For Line On Uart 5. mcause=0x8 mstatus=0x80 Wait For OK Message trap sequence verified Wait For Line On Uart Finished: PASSED matchNextLine=false Should Implement PMP Prepare Machine ${CURDIR}/pmp.elf Wait For Line On Uart Hello VeeR (M mode) Wait For Line On Uart VeeR does not have Smepmp Wait For Line On Uart PMP G=0, granularity is 4 Wait For Line On Uart 00 - User mode RWX in default state Wait For Line On Uart testing... Wait For Line On Uart hello Wait For Line On Uart pass Wait For Line On Uart 01 - User mode RWX with one (any) PMP region enabled Wait For Line On Uart testing... Wait For Line On Uart Trap! mcause=0x00000001, mepc=0x80000420, sp=0x80007E34 Wait For Line On Uart pass Wait For Line On Uart 02 - User mode RWX with code, data and stack access allowed Wait For Line On Uart testing... Wait For Line On Uart hello Wait For Line On Uart pass Wait For Line On Uart 03 - User mode (MPRV=0, MPP=0) --- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart Trap! mcause=0x00000007, mepc=0x8000046C, sp=0x80007E24 Wait For Line On Uart data mismatch Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart Trap! mcause=0x00000005, mepc=0x800004DC, sp=0x80007DD4 Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart Trap! mcause=0x00000001, mepc=0x80004040, sp=0x80007E34 Wait For Line On Uart pass Wait For Line On Uart 04 - User mode (MPRV=0, MPP=0) R-- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart Trap! mcause=0x00000007, mepc=0x8000046C, sp=0x80007E24 Wait For Line On Uart data mismatch Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart Trap! mcause=0x00000001, mepc=0x80004040, sp=0x80007E34 Wait For Line On Uart pass Wait For Line On Uart 05 - User mode (MPRV=0, MPP=0) -W- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart 06 - User mode (MPRV=0, MPP=0) RW- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart Trap! mcause=0x00000001, mepc=0x80004040, sp=0x80007E34 Wait For Line On Uart pass Wait For Line On Uart 07 - User mode (MPRV=0, MPP=0) --X from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart Trap! mcause=0x00000007, mepc=0x8000046C, sp=0x80007E24 Wait For Line On Uart data mismatch Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart Trap! mcause=0x00000005, mepc=0x800004DC, sp=0x80007DD4 Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 08 - User mode (MPRV=0, MPP=0) R-X from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart Trap! mcause=0x00000007, mepc=0x8000046C, sp=0x80007E24 Wait For Line On Uart data mismatch Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 09 - User mode (MPRV=0, MPP=0) -WX from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart 10 - User mode (MPRV=0, MPP=0) RWX from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 11 - Machine mode (MPRV=0, MPP=0) --- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 12 - Machine mode (MPRV=0, MPP=0) R-- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 13 - Machine mode (MPRV=0, MPP=0) -W- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart 14 - Machine mode (MPRV=0, MPP=0) RW- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 15 - Machine mode (MPRV=0, MPP=0) --X from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 16 - Machine mode (MPRV=0, MPP=0) R-X from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 17 - Machine mode (MPRV=0, MPP=0) -WX from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart 18 - Machine mode (MPRV=0, MPP=0) RWX from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 19 - Machine mode (MPRV=1, MPP=0) --- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart Trap! mcause=0x00000007, mepc=0x8000046C, sp=0x80007E34 Wait For Line On Uart data mismatch Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart Trap! mcause=0x00000005, mepc=0x800004DC, sp=0x80007DE4 Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 20 - Machine mode (MPRV=1, MPP=0) R-- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart Trap! mcause=0x00000007, mepc=0x8000046C, sp=0x80007E34 Wait For Line On Uart data mismatch Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 21 - Machine mode (MPRV=1, MPP=0) -W- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart 22 - Machine mode (MPRV=1, MPP=0) RW- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 23 - Machine mode (MPRV=1, MPP=0) --X from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart Trap! mcause=0x00000007, mepc=0x8000046C, sp=0x80007E34 Wait For Line On Uart data mismatch Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart Trap! mcause=0x00000005, mepc=0x800004DC, sp=0x80007DE4 Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 24 - Machine mode (MPRV=1, MPP=0) R-X from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart Trap! mcause=0x00000007, mepc=0x8000046C, sp=0x80007E34 Wait For Line On Uart data mismatch Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 25 - Machine mode (MPRV=1, MPP=0) -WX from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart 26 - Machine mode (MPRV=1, MPP=0) RWX from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 27 - Machine mode (MPRV=1, MPP=1) --- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 28 - Machine mode (MPRV=1, MPP=1) R-- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 29 - Machine mode (MPRV=1, MPP=1) -W- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart 30 - Machine mode (MPRV=1, MPP=1) RW- from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 31 - Machine mode (MPRV=1, MPP=1) --X from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 32 - Machine mode (MPRV=1, MPP=1) R-X from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 33 - Machine mode (MPRV=1, MPP=1) -WX from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart 34 - Machine mode (MPRV=1, MPP=1) RWX from designated areas Wait For Line On Uart configuring PMP... Wait For Line On Uart testing W... Wait For Line On Uart writing to .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing R... Wait For Line On Uart reading from .area... Wait For Line On Uart data match Wait For Line On Uart pass Wait For Line On Uart testing X... Wait For Line On Uart hello from .area Wait For Line On Uart pass Wait For Line On Uart 35 - Testing execution from a locked region in U and M mode Wait For Line On Uart testing from U mode... Wait For Line On Uart Trap! mcause=0x00000001, mepc=0x80004040, sp=0x80007E34 Wait For Line On Uart pass Wait For Line On Uart testing from M mode... Wait For Line On Uart Trap! mcause=0x00000001, mepc=0x80004040, sp=0x80007E44 Wait For Line On Uart pass Wait For Line On Uart attempting to unlock region... Wait For Line On Uart testing from U mode... Wait For Line On Uart Trap! mcause=0x00000001, mepc=0x80004040, sp=0x80007E34 Wait For Line On Uart pass Wait For Line On Uart testing from M mode... Wait For Line On Uart Trap! mcause=0x00000001, mepc=0x80004040, sp=0x80007E44 Wait For Line On Uart pass Wait For Line On Uart 36/36 passed Wait For Line On Uart Finished: PASSED matchNextLine=false ================================================ FILE: tools/renode/veer_smepmp.repl ================================================ mem: Memory.MappedMemory @sysbus 0x80000000 size: 0x10000000 htif_mem: Memory.MappedMemory @sysbus 0xD0580000 size: 0x1000 cpu: CPU.VeeR_EL2 @ sysbus cpuType: "rv32imc_zicsr_zifencei_zba_zbb_zbc_zbs_Smepmp" hartId: 0 dhry_mem: Memory.MappedMemory @sysbus 0xF0040000 size: 0x10000 ================================================ FILE: tools/riscof/README.md ================================================ # RISCOF for VeeR-EL2 Core This folder stores configuration files and plugins needed for running [RISCOF](https://riscof.readthedocs.io/en/stable/) tests for VeeR-EL2 Core. RISCOF is an official RISC-V core testing framework. Testing is done by executing predefined test programs on the simulated core (RTL simulation) and using an Instruction Set Simulator (ISS) followed comparing memory signatures. A memory signature is a memory region defined by a particular test program which content is compared. ## Install prerequisities 1. Verilator Installation instructions are available in the [Verilator's User Guide](https://veripool.org/guide/latest/install.html). Make sure that the verilator executable is available (eg. by setting `PATH`). 2. Spike (Instruction Set Simulator) Follow the instruction from the [documentation](https://github.com/riscv-software-src/riscv-isa-sim#build-steps). After installation make sure that the spike binary is visible in the current path. 3. RISC-V toolchain Download and install RISC-V GCC toolchain capable for targeting RV32IMC architecture. Depending on your system this may be done either via the system package manager or manually by downloading binaries / building them. ## Setup 1. Clone VeeR-EL2 Core repository with submodules and set `RV_ROOT` to the repository path: ``` git clone --recurse-submodules git@github.com:chipsalliance/Cores-VeeR-EL2.git cd Cores-Veer-EL2 export RV_ROOT=$(pwd) ``` 2. Build verilated model of VeeR-EL2 Core ``` ${RV_ROOT}/configs/veer.config make -f ${RV_ROOT}/tools/Makefile verilator-build ``` 3. Install RISCOF (in a Python virtual environment) ``` python3 -m venv env source env/bin/activate pip install git+https://github.com/riscv/riscof ``` 4. Clone RISCOF official tests The RISCOF framework uses manually developed official test programs. These need to be installed: ``` mkdir work cd work riscof --verbose info arch-test --clone ``` 5. Configure RISCOF Copy RISCOF configuration from VeeR-EL2 Core repository to the working directory and build the test list: ``` cp ${RV_ROOT}/tools/riscof/config.ini ./ cp -r ${RV_ROOT}/tools/riscof/spike ./ cp -r ${RV_ROOT}/tools/riscof/veer ./ riscof testlist --config=config.ini --suite=riscv-arch-test/riscv-test-suite/ --env=riscv-arch-test/riscv-test-suite/env ``` ## Running the tests To run the tests issue the following command. Once the tests finish a HTML report will be generated ``` riscof run --no-browser --config=config.ini --suite=riscv-arch-test/riscv-test-suite/ --env=riscv-arch-test/riscv-test-suite/env ``` ## CI RISCOF tests are run in CI. See `.github/workflows/test-riscof.yml` for GitHub actions workflow description. ================================================ FILE: tools/riscof/config.ini ================================================ [RISCOF] ReferencePlugin=spike ReferencePluginPath=spike DUTPlugin=veer DUTPluginPath=veer [veer] pluginpath=veer ispec=veer/veer_isa.yaml pspec=veer/veer_platform.yaml sim_binary=obj_dir/Vtb_top target_run=1 jobs=4 [spike] pluginpath=spike ispec=spike/spike_isa.yaml pspec=spike/spike_platform.yaml target_run=1 jobs=4 ================================================ FILE: tools/riscof/spike/env/link.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(rvtest_entry_point) SECTIONS { . = 0x80000000; .text.init : { *(.text.init) } . = ALIGN(0x1000); .tohost : { *(.tohost) } . = ALIGN(0x1000); .text : { *(.text) } . = ALIGN(0x1000); .data : { *(.data) } .data.string : { *(.data.string)} .bss : { *(.bss) } _end = .; } ================================================ FILE: tools/riscof/spike/env/model_test.h ================================================ #ifndef _COMPLIANCE_MODEL_H #define _COMPLIANCE_MODEL_H #define RVMODEL_DATA_SECTION \ .pushsection .tohost,"aw",@progbits; \ .align 8; .global tohost; tohost: .dword 0; \ .align 8; .global fromhost; fromhost: .dword 0; \ .popsection; \ .align 8; .global begin_regstate; begin_regstate: \ .word 128; \ .align 8; .global end_regstate; end_regstate: \ .word 4; //RV_COMPLIANCE_HALT #define RVMODEL_HALT \ li x1, 1; \ write_tohost: \ sw x1, tohost, t5; \ j write_tohost; #define MTIMECMP_BASE 0x2004000 #define RVMODEL_BOOT \ /* Set MTIMECMP to UINT64_MAX so that there isn't a timer interrupt pending in MIP */ \ li t0, -1; \ la t1, MTIMECMP_BASE; \ sw t0, (t1); \ sw t0, 4(t1); //RV_COMPLIANCE_DATA_BEGIN #define RVMODEL_DATA_BEGIN \ RVMODEL_DATA_SECTION \ .align 4;\ .global begin_signature; begin_signature: //RV_COMPLIANCE_DATA_END #define RVMODEL_DATA_END \ .align 4;\ .global end_signature; end_signature: //RVTEST_IO_INIT #define RVMODEL_IO_INIT //RVTEST_IO_WRITE_STR #define RVMODEL_IO_WRITE_STR(_R, _STR) //RVTEST_IO_CHECK #define RVMODEL_IO_CHECK() //RVTEST_IO_ASSERT_GPR_EQ #define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I) //RVTEST_IO_ASSERT_SFPR_EQ #define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) //RVTEST_IO_ASSERT_DFPR_EQ #define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) #define RVMODEL_SET_MSW_INT \ li t1, 1; \ li t2, 0x2000000; \ sw t1, 0(t2); #define RVMODEL_CLEAR_MSW_INT \ li t2, 0x2000000; \ sw x0, 0(t2); #define RVMODEL_CLEAR_MTIMER_INT #define RVMODEL_CLEAR_MEXT_INT #endif // _COMPLIANCE_MODEL_H ================================================ FILE: tools/riscof/spike/riscof_spike.py ================================================ import os import re import shutil import subprocess import shlex import logging import random import string from string import Template import sys import riscof.utils as utils import riscof.constants as constants from riscof.pluginTemplate import pluginTemplate logger = logging.getLogger() class spike(pluginTemplate): __model__ = "spike" __version__ = "1.0" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) config = kwargs.get('config') # If the config node for this DUT is missing or empty. Raise an error. At minimum we need # the paths to the ispec and pspec files if config is None: print("Please enter input file paths in configuration.") raise SystemExit(1) # In case of an RTL based DUT, this would be point to the final binary executable of your # test-bench produced by a simulator (like verilator, vcs, incisive, etc). In case of an iss or # emulator, this variable could point to where the iss binary is located. If 'PATH variable # is missing in the config.ini we can hardcode the alternate here. self.dut_exe = os.path.join(config['PATH'] if 'PATH' in config else "","spike") # Number of parallel jobs that can be spawned off by RISCOF # for various actions performed in later functions, specifically to run the tests in # parallel on the DUT executable. Can also be used in the build function if required. self.num_jobs = str(config['jobs'] if 'jobs' in config else 1) # Path to the directory where this python file is located. Collect it from the config.ini self.pluginpath=os.path.abspath(config['pluginpath']) # Collect the paths to the riscv-config absed ISA and platform yaml files. One can choose # to hardcode these here itself instead of picking it from the config.ini file. self.isa_spec = os.path.abspath(config['ispec']) self.platform_spec = os.path.abspath(config['pspec']) #We capture if the user would like the run the tests on the target or #not. If you are interested in just compiling the tests and not running #them on the target, then following variable should be set to False if 'target_run' in config and config['target_run']=='0': self.target_run = False else: self.target_run = True def initialise(self, suite, work_dir, archtest_env): # capture the working directory. Any artifacts that the DUT creates should be placed in this # directory. Other artifacts from the framework and the Reference plugin will also be placed # here itself. self.work_dir = work_dir # capture the architectural test-suite directory. self.suite_dir = suite # Note the march is not hardwired here, because it will change for each # test. Similarly the output elf name and compile macros will be assigned later in the # runTests function self.compile_cmd = 'riscv64-unknown-elf-gcc -march={0} \ -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -g\ -T '+self.pluginpath+'/env/link.ld\ -I '+self.pluginpath+'/env/\ -I ' + archtest_env + ' {2} -o {3} {4}' # add more utility snippets here def build(self, isa_yaml, platform_yaml): # load the isa yaml as a dictionary in python. ispec = utils.load_yaml(isa_yaml)['hart0'] # capture the XLEN value by picking the max value in 'supported_xlen' field of isa yaml. This # will be useful in setting integer value in the compiler string (if not already hardcoded); self.xlen = ('64' if 64 in ispec['supported_xlen'] else '32') # for spike start building the '--isa' argument. the self.isa is dutnmae specific and may not be # useful for all DUTs self.isa = 'rv' + self.xlen if "I" in ispec["ISA"]: self.isa += 'i' if "M" in ispec["ISA"]: self.isa += 'm' if "F" in ispec["ISA"]: self.isa += 'f' if "D" in ispec["ISA"]: self.isa += 'd' if "C" in ispec["ISA"]: self.isa += 'c' #TODO: The following assumes you are using the riscv-gcc toolchain. If # not please change appropriately self.compile_cmd = self.compile_cmd+' -mabi='+('lp64 ' if 64 in ispec['supported_xlen'] else 'ilp32 ') def runTests(self, testList): # Delete Makefile if it already exists. makefile = self.work_dir + "/Makefile." + self.name[:-1] if os.path.exists(makefile): os.remove(makefile) # create an instance the makeUtil class that we will use to create targets. make = utils.makeUtil(makefilePath=makefile) # set the make command that will be used. The num_jobs parameter was set in the __init__ # function earlier make.makeCommand = 'make -k -j' + self.num_jobs # we will iterate over each entry in the testList. Each entry node will be refered to by the # variable testname. for testname in testList: # for each testname we get all its fields (as described by the testList format) testentry = testList[testname] # we capture the path to the assembly file of this test test = testentry['test_path'] # capture the directory where the artifacts of this test will be dumped/created. RISCOF is # going to look into this directory for the signature files test_dir = testentry['work_dir'] # name of the elf file after compilation of the test elf = 'my.elf' # name of the signature file as per requirement of RISCOF. RISCOF expects the signature to # be named as DUT-.signature. The below variable creates an absolute path of # signature file. sig_file = os.path.join(test_dir, self.name[:-1] + ".signature") # Save Spike's execution log exec_log_file = os.path.join(test_dir, "exec.log") # for each test there are specific compile macros that need to be enabled. The macros in # the testList node only contain the macros/values. For the gcc toolchain we need to # prefix with "-D". The following does precisely that. compile_macros= ' -D' + " -D".join(testentry['macros']) # substitute all variables in the compile command that we created in the initialize # function isa = testentry['isa'].lower() # Force the zicsr extension to -march. # Some tests seem to depend on it in order to compile at all, despite it not being in testentry? if "zicsr" not in isa: isa += "_zicsr" cmd = self.compile_cmd.format(isa, self.xlen, test, elf, compile_macros) # if the user wants to disable running the tests and only compile the tests, then # the "else" clause is executed below assigning the sim command to simple no action # echo statement. if self.target_run: # set up the simulation command. Template is for spike. Please change. simcmd = self.dut_exe + ' -l --log={3} --misaligned --isa={0} +signature={1} +signature-granularity=4 {2}'.format(self.isa, sig_file, elf, exec_log_file) else: simcmd = 'echo "NO RUN"' # concatenate all commands that need to be executed within a make-target. execute = '@cd {0}&& {1}&& {2}'.format(testentry['work_dir'], cmd, simcmd) # create a target. The makeutil will create a target with the name "TARGET" where num # starts from 0 and increments automatically for each new target that is added make.add_target(execute) # once the make-targets are done and the makefile has been created, run all the targets in # parallel using the make command set above. make.execute_all(self.work_dir, timeout=7200) # if target runs are not required then we simply exit as this point after running all # the makefile targets. if not self.target_run: raise SystemExit(0) ================================================ FILE: tools/riscof/spike/spike_isa.yaml ================================================ hart_ids: [0] hart0: ISA: RV32IMCZicsr_Zifencei physical_addr_sz: 32 User_Spec_Version: '2.3' supported_xlen: [32] hw_data_misaligned_support: true misa: reset-val: 0x40001104 rv32: accessible: true mxl: implemented: true type: warl: dependency_fields: [] legal: - mxl[1:0] in [0x1] wr_illegal: - Unchanged extensions: implemented: true type: warl: dependency_fields: [] legal: - extensions[25:0] bitmask [0x0001104, 0x0000000] wr_illegal: - Unchanged ================================================ FILE: tools/riscof/spike/spike_platform.yaml ================================================ mtime: implemented: true address: 0xbff8 mtimecmp: implemented: true address: 0x4000 nmi: label: nmi_vector reset: label: reset_vector ================================================ FILE: tools/riscof/veer/env/link.ld ================================================ OUTPUT_ARCH( "riscv" ) ENTRY(rvtest_entry_point) SECTIONS { . = 0x80000000; .text.init : { *(.text.init) } . = ALIGN(0x1000); .text : { *(.text) } . = ALIGN(0x1000); .data : { *(.data) } .data.string : { *(.data.string)} .bss : { *(.bss) } _end = .; . = 0xd0580000; .tohost : { *(.tohost) } } ================================================ FILE: tools/riscof/veer/env/model_test.h ================================================ #ifndef _COMPLIANCE_MODEL_H #define _COMPLIANCE_MODEL_H #define RVMODEL_DATA_SECTION \ .pushsection .tohost,"aw",@progbits; \ .align 8; .global tohost; tohost: .dword 0; \ .align 8; .global fromhost; fromhost: .dword 0; \ .popsection; \ .align 8; .global begin_regstate; begin_regstate: \ .word 128; \ .align 8; .global end_regstate; end_regstate: \ .word 4; //RV_COMPLIANCE_HALT #define RVMODEL_HALT \ li x1, 0xFF; \ write_tohost: \ sw x1, tohost, t5; \ j write_tohost; #define RVMODEL_BOOT \ /* Length of RVMODEL_BOOT must be the same in both VeeR and Spike, to align PC */ \ .rept 4; \ nop; \ .endr; //RV_COMPLIANCE_DATA_BEGIN #define RVMODEL_DATA_BEGIN \ RVMODEL_DATA_SECTION \ .align 4;\ .global begin_signature; begin_signature: //RV_COMPLIANCE_DATA_END #define RVMODEL_DATA_END \ .align 4;\ .global end_signature; end_signature: //RVTEST_IO_INIT #define RVMODEL_IO_INIT //RVTEST_IO_WRITE_STR #define RVMODEL_IO_WRITE_STR(_R, _STR) //RVTEST_IO_CHECK #define RVMODEL_IO_CHECK() //RVTEST_IO_ASSERT_GPR_EQ #define RVMODEL_IO_ASSERT_GPR_EQ(_S, _R, _I) //RVTEST_IO_ASSERT_SFPR_EQ #define RVMODEL_IO_ASSERT_SFPR_EQ(_F, _R, _I) //RVTEST_IO_ASSERT_DFPR_EQ #define RVMODEL_IO_ASSERT_DFPR_EQ(_D, _R, _I) #define RVMODEL_SET_MSW_INT \ li t1, 1; \ li t2, 0x2000000; \ sw t1, 0(t2); #define RVMODEL_CLEAR_MSW_INT \ li t2, 0x2000000; \ sw x0, 0(t2); #define RVMODEL_CLEAR_MTIMER_INT #define RVMODEL_CLEAR_MEXT_INT #endif // _COMPLIANCE_MODEL_H ================================================ FILE: tools/riscof/veer/riscof_veer.py ================================================ import os import re import shutil import subprocess import shlex import logging import random import string from string import Template import sys import riscof.utils as utils import riscof.constants as constants from riscof.pluginTemplate import pluginTemplate logger = logging.getLogger() class veer(pluginTemplate): __model__ = "VeeR" __version__ = "1.0" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) config = kwargs.get('config') # If the config node for this DUT is missing or empty. Raise an error. At minimum we need # the paths to the ispec and pspec files if config is None: print("Please enter input file paths in configuration.") raise SystemExit(1) # Number of parallel jobs that can be spawned off by RISCOF # for various actions performed in later functions, specifically to run the tests in # parallel on the DUT executable. Can also be used in the build function if required. self.num_jobs = str(config['jobs'] if 'jobs' in config else 1) # Path to the directory where this python file is located. Collect it from the config.ini self.pluginpath = os.path.abspath(config['pluginpath']) # Collect the paths to the riscv-config absed ISA and platform yaml files. One can choose # to hardcode these here itself instead of picking it from the config.ini file. self.isa_spec = os.path.abspath(config['ispec']) self.platform_spec = os.path.abspath(config['pspec']) # We capture if the user would like the run the tests on the target or # not. If you are interested in just compiling the tests and not running # them on the target, then following variable should be set to False if 'target_run' in config and config['target_run']=='0': self.target_run = False else: self.target_run = True # Verilated simulation binary path self.sim_binary = os.path.abspath(config['sim_binary']) def initialise(self, suite, work_dir, archtest_env): # capture the working directory. Any artifacts that the DUT creates should be placed in this # directory. Other artifacts from the framework and the Reference plugin will also be placed # here itself. self.work_dir = work_dir # capture the architectural test-suite directory. self.suite_dir = suite # Note the march is not hardwired here, because it will change for each # test. Similarly the output elf name and compile macros will be assigned later in the # runTests function self.compile_cmd = 'riscv64-unknown-elf-gcc -march={0} \ -static -mcmodel=medany -fvisibility=hidden -nostdlib -nostartfiles -g\ -T '+self.pluginpath+'/env/link.ld\ -I '+self.pluginpath+'/env/\ -I ' + archtest_env + ' {2} -o {3} {4}' # Conversion command. Make a HEX file from the ELF for the verilated # simulation self.convert_cmd = 'riscv64-unknown-elf-objcopy -O verilog {3} program.hex' # Symbol address extraction command self.symbols_cmd = 'riscv64-unknown-elf-nm -B -n {3} > program.sym' def build(self, isa_yaml, platform_yaml): # load the isa yaml as a dictionary in python. ispec = utils.load_yaml(isa_yaml)['hart0'] # capture the XLEN value by picking the max value in 'supported_xlen' field of isa yaml. This # will be useful in setting integer value in the compiler string (if not already hardcoded); self.xlen = ('64' if 64 in ispec['supported_xlen'] else '32') # for veer start building the '--isa' argument. the self.isa is dutnmae specific and may not be # useful for all DUTs self.isa = 'rv' + self.xlen if "I" in ispec["ISA"]: self.isa += 'i' if "M" in ispec["ISA"]: self.isa += 'm' if "F" in ispec["ISA"]: self.isa += 'f' if "D" in ispec["ISA"]: self.isa += 'd' if "C" in ispec["ISA"]: self.isa += 'c' self.compile_cmd = self.compile_cmd+' -mabi='+('lp64 ' if 64 in ispec['supported_xlen'] else 'ilp32 ') def runTests(self, testList): # Delete Makefile if it already exists. makefile = self.work_dir + "/Makefile." + self.name[:-1] if os.path.exists(makefile): os.remove(makefile) # create an instance the makeUtil class that we will use to create targets. make = utils.makeUtil(makefilePath=makefile) # set the make command that will be used. The num_jobs parameter was set in the __init__ # function earlier make.makeCommand = 'make -k -j' + self.num_jobs # we will iterate over each entry in the testList. Each entry node will be refered to by the # variable testname. for testname in testList: # for each testname we get all its fields (as described by the testList format) testentry = testList[testname] # we capture the path to the assembly file of this test test = testentry['test_path'] # capture the directory where the artifacts of this test will be dumped/created. RISCOF is # going to look into this directory for the signature files test_dir = testentry['work_dir'] # name of the elf file after compilation of the test elf = 'my.elf' # name of the signature file as per requirement of RISCOF. RISCOF expects the signature to # be named as DUT-.signature. The below variable creates an absolute path of # signature file. sig_file = os.path.join(test_dir, self.name[:-1] + ".signature") # for each test there are specific compile macros that need to be enabled. The macros in # the testList node only contain the macros/values. For the gcc toolchain we need to # prefix with "-D". The following does precisely that. compile_macros= ' -D' + " -D".join(testentry['macros']) # substitute all variables in the commands that we created in the initialize # function isa = testentry['isa'].lower() # Force the zicsr extension to -march. # Some tests seem to depend on it in order to compile at all, despite it not being in testentry? if "zicsr" not in isa: isa += "_zicsr" cmds = [ self.compile_cmd.format(isa, self.xlen, test, elf, compile_macros), self.convert_cmd.format(isa, self.xlen, test, elf), self.symbols_cmd.format(isa, self.xlen, test, elf), ] # if the user wants to disable running the tests and only compile the tests, then # the "else" clause is executed below assigning the sim command to simple no action # echo statement. if self.target_run: simcmd = [ self.sim_binary + " --symbols program.sym", 'mv veer.signature DUT-{}.signature'.format(veer.__model__), ] else: simcmd = [ 'echo "NO RUN"', ] # concatenate all commands that need to be executed within a make-target. execute = 'cd ' + testentry['work_dir'] + '&& ' execute += '&& '.join(cmds + simcmd) # create a target. The makeutil will create a target with the name "TARGET" where num # starts from 0 and increments automatically for each new target that is added make.add_target(execute) # once the make-targets are done and the makefile has been created, run all the targets in # parallel using the make command set above. make.execute_all(self.work_dir, timeout=7200) # if target runs are not required then we simply exit as this point after running all # the makefile targets. if not self.target_run: raise SystemExit(0) ================================================ FILE: tools/riscof/veer/veer_isa.yaml ================================================ hart_ids: [0] hart0: ISA: RV32IMCZicsr physical_addr_sz: 32 User_Spec_Version: '2.3' supported_xlen: [32] hw_data_misaligned_support: true misa: reset-val: 0x40001104 rv32: accessible: true mxl: implemented: true type: warl: dependency_fields: [] legal: - mxl[1:0] in [0x1] wr_illegal: - Unchanged extensions: implemented: true type: warl: dependency_fields: [] legal: - extensions[25:0] bitmask [0x0001104, 0x0000000] wr_illegal: - Unchanged ================================================ FILE: tools/riscof/veer/veer_platform.yaml ================================================ mtime: implemented: true address: 0xbff8 mtimecmp: implemented: true address: 0x4000 nmi: label: nmi_vector reset: label: reset_vector ================================================ FILE: tools/riscv-dv/Makefile ================================================ SHELL = /bin/bash -o pipefail GCC_PREFIX ?= riscv64-unknown-elf RISCV_DV_PATH = $(RV_ROOT)/third_party/riscv-dv RISCV_DV_SIM ?= pyflow RISCV_DV_ISS ?= spike RISCV_DV_TEST ?= riscv_arithmetic_basic_test RISCV_DV_SEED ?= 999 RISCV_DV_ITER ?= 1 RISCV_DV_BATCH ?= 1 RISCV_DV_PRIV ?= m export RISCV_GCC ?= $(GCC_PREFIX)-gcc export RISCV_OBJCOPY ?= $(GCC_PREFIX)-objcopy export RISCV_NM ?= $(GCC_PREFIX)-nm WORK_DIR ?= work TEST_DIR = $(WORK_DIR)/test_$(RISCV_DV_TEST) SIM_DIR = $(TEST_DIR)/hdl_sim ifeq ($(findstring u, $(RISCV_DV_PRIV)), u) VEER_EXTRA_CONF = "-set=user_mode=1 -set=smepmp=1" else VEER_EXTRA_CONF = "" endif VEER_TARGET = default VEER_CONF = -set build_axi4 \ -set reset_vec=0x80000000 \ -set fpga_optimize=0 \ $(VEER_EXTRA_CONF) # Coverage reporting ifeq ("$(COVERAGE)", "all") VERILATOR_COVERAGE = --coverage else ifeq ("$(COVERAGE)", "branch") VERILATOR_COVERAGE = --coverage-line else ifeq ("$(COVERAGE)", "toggle") VERILATOR_COVERAGE = --coverage-toggle else ifeq ("$(COVERAGE)", "functional") VERILATOR_COVERAGE = --coverage-user else ifneq ("$(COVERAGE)", "") $(error Unknown COVERAGE value '$(COVERAGE)') endif VERILATOR = verilator VERILATOR_CFLAGS= "-std=c++14" VERILATOR_INC = -I$(WORK_DIR) -I$(RV_ROOT)/testbench VERILATOR_EXE = $(RV_ROOT)/testbench/test_tb_top.cpp # Set `TB_SILENT_FAIL` as generated instruction sequences may cause TB errors # Errors are to be reported when execution flows discrepancy is encountered VERILATOR_EXTRA_DEFS = +define+TB_SILENT_FAIL HDL_FILES = $(WORK_DIR)/common_defines.vh \ $(WORK_DIR)/el2_pdef.vh \ $(RV_ROOT)/testbench/tb_top_pkg.sv \ $(RV_ROOT)/testbench/tb_top.sv \ $(RV_ROOT)/testbench/ahb_sif.sv \ $(RV_ROOT)/design/include/el2_def.sv # Determine verilator version if possible. Set the flag accordingly. Since # version v5.006 -Wno-IMPLICIT was renamed to -Wno-IMPLICITSTATIC VERILATOR_NOIMPLICIT := -Wno-IMPLICITSTATIC VERILATOR_VERSION := $(subst .,,$(word 2,$(shell $(VERILATOR) --version))) ifeq ("$(.SHELLSTATUS)", "0") $(shell test $(VERILATOR_VERSION) -lt 5006) ifeq ("$(.SHELLSTATUS)", "0") VERILATOR_NOIMPLICIT := -Wno-IMPLICIT endif endif ISA_STRING = rv32imc_zicsr_zifencei_zba_zbb_zbc_zbs # If compiled with U-mode we implicitly also compile with Smepmp in these tests ifeq ($(findstring u, $(RISCV_DV_PRIV)), u) ISA_STRING := "${ISA_STRING}"_smepmp endif RISCV_DV_SIM_ARGS= \ --priv ${RISCV_DV_PRIV} # Append Renode-specific options ifeq ("$(RISCV_DV_ISS)", "renode") ISS_OPTS += --cpu-type='VeeR_EL2' ISS_OPTS += --additional-cpu-parameters='' RISCV_DV_SIM_ARGS += \ --iss_opts=" ${ISS_OPTS} " endif # riscv-dv args RISCV_DV_ARGS = \ --simulator $(RISCV_DV_SIM) \ --test $(RISCV_DV_TEST) \ --iss $(RISCV_DV_ISS) \ --iss_timeout 120 \ --start_seed $(RISCV_DV_SEED) \ --iterations $(RISCV_DV_ITER) \ --batch_size $(RISCV_DV_BATCH) \ --isa ${ISA_STRING} \ --mabi ilp32 \ --custom_target $(PWD) \ --testlist $(PWD)/testlist.yaml \ -v -o $(TEST_DIR) MAKEFILE = $(abspath $(MAKEFILE_LIST)) all: @echo "Use 'make run'" # Directory rules $(WORK_DIR): mkdir -p $@ $(TEST_DIR): mkdir -p $@ # VeeR config $(WORK_DIR)/defines.h: | $(WORK_DIR) BUILD_PATH=$(WORK_DIR) $(RV_ROOT)/configs/veer.config -target=$(VEER_TARGET) $(VEER_CONF) echo '`undef RV_ASSERT_ON' >> $(WORK_DIR)/common_defines.vh # Verilated testbench rules $(WORK_DIR)/verilator/Vtb_top.mk: $(WORK_DIR)/defines.h $(VERILATOR) --cc -CFLAGS $(VERILATOR_CFLAGS) $(VERILATOR_INC) $(VERILATOR_EXTRA_DEFS)\ $(HDL_FILES) -f $(RV_ROOT)/testbench/flist --top-module tb_top \ -exe $(VERILATOR_EXE) -Wno-WIDTH -Wno-UNOPTFLAT $(VERILATOR_NOIMPLICIT) --autoflush \ --timing $(VERILATOR_COVERAGE) -fno-table -Wno-LATCH\ -Mdir $(WORK_DIR)/verilator $(WORK_DIR)/verilator/Vtb_top: $(WORK_DIR)/verilator/Vtb_top.mk $(MAKE) -C $(WORK_DIR)/verilator -f Vtb_top.mk OPT_FAST="-O3" # Code generation $(TEST_DIR)/generate.log: | $(TEST_DIR) PYTHONPATH=$(RISCV_DV_PATH)/pygen python3 $(RISCV_DV_PATH)/run.py $(RISCV_DV_ARGS) \ --steps gen @touch $@ # Code patching & compilation # remove _smepmp from ISA string, as it's not recognized by GCC $(TEST_DIR)/compile.log: $(TEST_DIR) # Patch the code find $(TEST_DIR)/asm_test -name "*.S" -exec python3 code_fixup.py -i {} -o {} \; # Compile, simulate PYTHONPATH=$(RISCV_DV_PATH)/pygen python3 $(RISCV_DV_PATH)/run.py $(subst _smepmp,,$(RISCV_DV_ARGS)) \ --steps gcc_compile 2>&1 | tee $@ # ISS simulation $(TEST_DIR)/iss_sim.log: $(TEST_DIR)/compile.log | $(TEST_DIR) # Compile, simulate PYTHONPATH=$(RISCV_DV_PATH)/pygen python3 $(RISCV_DV_PATH)/run.py $(RISCV_DV_ARGS) $(RISCV_DV_SIM_ARGS) \ --steps iss_sim 2>&1 | tee $@ if grep -q ERROR $(TEST_DIR)/iss_sim.log; then \ echo "ISS simulation failed"; \ exit 1; \ fi # Tests are built by `run.py` script, they shouldn't be constructed by this Makefile directly %.o: $(warning There are additional test files ($@), which will not be compiled. Hint: you might need to set "RISCV_DV_ITER" to a higher value) # Generate symbols of executables %.sym: %.o $(RISCV_NM) -B -n $< > $@ # Convert executables %.hex: %.o $(RISCV_OBJCOPY) -O verilog $< $@ # HDL simulation $(SIM_DIR)/%.log: $(TEST_DIR)/asm_test/%.hex $(TEST_DIR)/asm_test/%.sym $(WORK_DIR)/verilator/Vtb_top mkdir -p $(basename $@) cp $< $(basename $@)/program.hex cp $(basename $<).sym $(basename $@)/program.sym cd $(basename $@) && $(abspath $(WORK_DIR)/verilator/Vtb_top) --symbols program.sym --mailbox-sym tohost mv $(basename $@)/exec.log $@ # Log conversion rules $(TEST_DIR)/spike_sim/%.csv: $(TEST_DIR)/spike_sim/%.log python3 $(RISCV_DV_PATH)/scripts/spike_log_to_trace_csv.py --log $< --csv $@ $(TEST_DIR)/renode_sim/%.csv: $(TEST_DIR)/renode_sim/%.log python3 $(RISCV_DV_PATH)/scripts/renode_log_to_trace_csv.py --log $< --csv $@ $(SIM_DIR)/%.csv: $(SIM_DIR)/%.log veer_log_to_trace_csv.py PYTHONPATH=$(RISCV_DV_PATH)/scripts python3 veer_log_to_trace_csv.py --log $< --csv $@ # Trace comparison $(TEST_DIR)/comp_%.log: $(TEST_DIR)/$(RISCV_DV_ISS)_sim/%.csv $(SIM_DIR)/%.csv rm -rf $@ python3 $(RISCV_DV_PATH)/scripts/instr_trace_compare.py \ --csv_file_1 $(word 1, $^) --csv_name_1 ISS --csv_file_2 $(word 2, $^) --csv_name_2 HDL \ --in_order_mode 1 --log $@ --verbose 10 --mismatch_print_limit 20 cat $@ %.sv: %.py ./$< $(RISCV_DV_PATH) $(RV_ROOT) > $@ generate: # Generate *.sv configuration #$(MAKE) -f $(MAKEFILE) riscv_core_setting.sv # Run RISC-V DV code generation $(MAKE) -f $(MAKEFILE) $(TEST_DIR)/generate.log compile: $(TEST_DIR)/compile.log | $(TEST_DIR) find $(TEST_DIR)/asm_test -name "*.S" | sed 's|\.S|.hex|g' | xargs $(MAKE) -f $(MAKEFILE) run: # Run RISC-V DV compilation and simulation $(MAKE) -f $(MAKEFILE) $(TEST_DIR)/iss_sim.log # Run HDL simulation(s) and trace comparison find $(TEST_DIR)/$(RISCV_DV_ISS)_sim -name "*.log" | sed 's|sim/|sim/../comp_|g' | xargs realpath --relative-to=$(PWD) | xargs $(MAKE) -f $(MAKEFILE) # Check for errors for F in $(TEST_DIR)/comp_*.log; do grep "\[PASSED\]" $$F; if [ $$? -ne 0 ]; then exit 255; fi; done clean: rm -rf $(TEST_DIR) fullclean: rm -rf $(WORK_DIR) .PHONY: all generate run clean fullclean .SECONDARY: # Disable any default actions Makefile might invoke for suffix rules (e.g. invoking CC for our tests) .SUFFIXES: ================================================ FILE: tools/riscv-dv/README.md ================================================ # RISCV-DV for VeeR-EL2 Core This folder contains utilities necessary for running [RISCV-DV](https://htmlpreview.github.io/?https://github.com/google/riscv-dv/blob/master/docs/build/singlehtml/index.html#) tests with VeeR-EL2 Core as well as the master Makefile which facilitates the process. RISCV-DV is a framework for testing RISC-V cores by generating random instructions, executing them in a reference ISS (instruction set simulator) as well as on the tested core (RTL simulation) and comparing execution trace logs. The trace logs contain executed instructions and core state changes (register writes) after each one which allows to precisely track the core behavior. ## Setup 1. Clone VeeR-EL2 Core repository with submodules and set `RV_ROOT` to the repository path: ``` git clone --recurse-submodules git@github.com:chipsalliance/Cores-VeeR-EL2.git cd Cores-Veer-EL2 export RV_ROOT=$(pwd) ``` 2. Setup the RISCV-DV framework The framework should be already cloned in `Cores-Veer-EL2/third_party/riscv-dv`. Install its dependencies, best using a Python virtual environment: ``` python3 -m venv env source env/bin/activate pip install -r ${RV_ROOT}/third_party/riscv-dv/requirements.txt ``` 3. Setup Verilator Installation instructions are available in the [Verilator's User Guide](https://veripool.org/guide/latest/install.html). Make sure that the verilator executable is available (eg. by setting `PATH`). 4. Setup instruction set simulator (ISS) RISCV-DV tests require a reference RISC-V program executor in a form of instruction set simulator. The RISCV-DV flow for VeeR-EL2 Core supports three of them: - Spike Follow the instruction from the [documentation](https://github.com/riscv-software-src/riscv-isa-sim#build-steps). After installation make sure that the spike binary is visible in the current path. - Renode [Renode](www.renode.io) is a full-fledged embedded system simulator developed at Antmicro. Its capabilities go beyond simulating a RISC-V core. In configuration for RISCV-DV only basic features are used just to be able to produce execution trace log. Renode can be downloaded as a pre-built binary. Download the latest "linux-portable" release from https://github.com/renode/renode/releases and unpack it. For example: ``` wget https://github.com/renode/renode/releases/download/v1.13.3/renode-1.13.3.linux-portable.tar.gz tar -zxf renode-1.13.3.linux-portable.tar.gz export PATH=${PATH}:`realpath renode_1.13.3_portable` ``` 5. Setup RISC-V toolchain Download and install RISC-V GCC toolchain capable for targeting RV32IMC architecture. Depending on your system this may be done either via the system package manager or manually by downloading binaries / building them. Export environmental variables required by RISCV-DV: ``` export RISCV_TOOLCHAIN= export RISCV_GCC="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-gcc" export RISCV_OBJCOPY="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-objcopy" export RISCV_NM="$RISCV_TOOLCHAIN/bin/riscv32-unknown-elf-nm" ``` ## Running tests To run the tests using the default setup do the following: ``` cd ${RV_ROOT}/tools/riscv-dv make run ``` Test execution environment is configurable by setting environment variables, which can be done either in the `Makefile` or in the CLI command,e.g; ``` RISCV_DV_ISS=whisper` make all ``` Full list of supported options is presented in the table below: | Variable | Default value | Allowed values | Description | | :---------------: | :----------------------------:| :-------------------------------: | :-------------------------------------------------------: | | `RISCV_DV_ISS` | `spike` | `spike`, `whisper`, `renode` | Controls which ISS is used as the reference. | | `RISCV_DV_TEST` | `riscv_arithmetic_basic_test` | | Test name. The complete list of tests can be found in [RISCV-DV documentation](https://github.com/chipsalliance/riscv-dv/tree/master/pygen/pygen_src) | | `RISCV_DV_ITER` | 1 | >= 1 | Test iteration count, default 1. | | `RISCV_DV_BATCH` | 1 | >= 1 | Test batch count, default 1. | | `RISCV_DV_SEED` | 999 | | Random generator seed for RISCV-DV instruction randomizer.| | `COVERAGE` | | `branch`, `toggle`, `functional` | Enables coverage data collection in Verilator. More information about coverage in Verilator can be found in its [documentation](https://veripool.org/guide/latest/simulating.html#coverage-analysis). | ## CI RISCV-DV tests are run in GitHub actions CI. The workflow responsible for them can be found at `.github/workflows/test-riscv-dv.yml` ================================================ FILE: tools/riscv-dv/code_fixup.py ================================================ #!/usr/bin/env python3 import argparse import re # ============================================================================= class AssemblyLine: """ Simple assembly line representation """ RE_INSTR = re.compile(r"(?P\S+)\s+(?P.*)") def __init__(self, text): self.text = text self.mnemonic = None self.operands = None # Strip label if any if ":" in text: text = text.split(":", maxsplit=1)[1] # Strip comment if any if "#" in text: text = text.split("#", maxsplit=1)[0] # Get instruction and operands m = self.RE_INSTR.match(text.strip()) if m is not None: if m.group("mnemonic")[0] == ".": return self.mnemonic = m.group("mnemonic").lower() self.operands = [op.strip() for op in m.group("operands").split(",")] def __str__(self): return self.text # ============================================================================= MNEMONICS = {"div", "divu", "rem", "remu", "lb", "lbu", "lh", "lhu", "lw", "c.lw", "c.lwsp"} def main(): parser = argparse.ArgumentParser() parser.add_argument( "-i", type=str, required=True, help="Input assembly file" ) parser.add_argument( "-o", type=str, required=True, help="Output assembly file" ) args = parser.parse_args() max_nops = 10 # Read and parse with open(args.i, "r") as fp: inp_lines = [AssemblyLine(l) for l in fp.readlines()] # Identify a delayed write instruction followed by another one which writes # to the same register out_lines = [] for i in range(len(inp_lines)): line = inp_lines[i] out_lines.append(line) # Bypass if not line.mnemonic: continue # Check if it is a delayed write. If not then bypass is_delayed = line.mnemonic in MNEMONICS if not is_delayed: continue # Get next 2 instructions following = [] for j in range(i+1, len(inp_lines)): if inp_lines[j].mnemonic is not None: following.append(inp_lines[j]) if len(following) >= 2: break # If any of the instructions targets the same register insert NOPs dst = line.operands[0] for j, l in enumerate(following): if l.operands and l.operands[0] == dst: nops = max(0, max_nops - j) pad = " " * 18 out_lines.append(pad + "# FIXME: Inserting {} NOPs to prevent VeeR from cancelling a delayed write #\n".format(nops)) for k in range(nops): out_lines.append(pad + "nop\n") out_lines.append(pad + "# end of nop insertion #\n") break # Write with open(args.o, "w") as fp: for l in out_lines: fp.write(str(l)) if __name__ == "__main__": main() ================================================ FILE: tools/riscv-dv/riscv_core_setting.py ================================================ #!/usr/bin/env python3 import argparse import hashlib import logging import re from pathlib import Path from typing import Dict, List, Set logger = logging.getLogger(__name__) RISCV_INSTR_PKG_REL_PATH = "src/riscv_instr_pkg.sv" RISCV_INSTR_PKG_SHA = "90b58f1c998f1116fb4ff8c652a7e7fe4345867739ac4f6f852f452427b0ebed" VEER_DECODE_REL_PATH = "design/dec/decode" VEER_DECODE_SHA = "62dc85fad17b27d041678447c401bfee9725d6889a8d4cb68b9e38c34a6b8e79" VEER_CSRDECODE_REL_PATH = "design/dec/csrdecode" VEER_CSRDECODE_SHA = "f5ba0a4da487c6f760d20467b4647018eef196b2ad7956f7ee86cea29375796d" VEER_EL2_DEC_TLU_CTRL_PATH = "design/dec/el2_dec_tlu_ctl.sv" VEER_EL2_DEC_TLU_CTRL_SHA = "d472b88fd419f8ebd8e1db3ee701b464d02a3cffd8de01aeb702d600736ec547" def check_sha256(path: Path, exp_sha256: str): with open(path, "rb") as fd: sha256 = hashlib.sha256(fd.read()) if sha256.hexdigest() != exp_sha256: logger.warning( f"Script prepared for a different version of {path} file. ({sha256.hexdigest()} vs {exp_sha256})" ) logger.warning("Verify if the output is correct") def _parse_enum_with_one_hex(content: List[str], regexp: str, lower: int, upper: int) -> Dict[str, int]: result = {} for i, line in enumerate(content[lower:upper]): reg_data = re.findall(regexp, line) if len(reg_data) == 0: continue if len(reg_data) > 1: raise Exception("Found more matching values than expected") (name, str_val) = reg_data[0] val = int(str_val, 16) result[val] = name return result def _parse_enum_with_insn(content: List[str], lower: int, upper: int): insn_to_cat = {} category = "" for i, line in enumerate(content[lower:upper]): reg_insn = re.findall(r"^\s*(? 0 and len(reg_insn_comment) > 0) or (len(reg_insn) > 1) or (len(reg_insn_comment) > 1) ): raise Exception("Found different number of matchin values than expected") if len(reg_insn_comment) == 1: category = reg_insn_comment[0] if len(reg_insn) == 1: insn_name = reg_insn[0] if category == "": raise Exception("Instruction category not found") insn_to_cat[insn_name] = category return insn_to_cat def parse_riscv_instr_pkg(riscv_instr_pkg_path: Path): """Parses riscv_instr_pkg.sv and returns dictionaries with defined enums""" with open(riscv_instr_pkg_path) as fd: content = fd.readlines() csrs = _parse_enum_with_one_hex(content, r"(\S+)\s*=\s*'h([0-9a-zA-Z]+)", 749, 1101) intr = _parse_enum_with_one_hex(content, r"(\S+)\s*=\s*4'h([0-9a-zA-Z]+)", 1146, 1156) excp = _parse_enum_with_one_hex(content, r"(\S+)\s*=\s*4'h([0-9a-zA-Z]+)", 1158, 1173) insn = _parse_enum_with_insn(content, 115, 649) return (csrs, intr, excp, insn) def _parse_veer_decode(content: List[str], lower: int, upper: int, replace_dict: Dict[str, str] = {}): regexp = r"^\s*(? 1: raise Exception("Found more matching values than expected") (name, str_val) = reg_data[0] veer_csrs[name] = str_val return veer_csrs def parse_veer_csrdecode(csrdecode_path: Path): with open(csrdecode_path) as fd: content = fd.readlines() return _parse_veer_csrdecode(content, 4, 82) def _parse_veer_irqs_and_excp(content: List[str], lower: int, upper: int): regexp = r"\{5\{.*\}\}\s*&\s*5'h([a-zA-Z0-9]+)" result = set() for i, line in enumerate(content[lower:upper]): reg_data = re.findall(regexp, line) if len(reg_data) == 0: continue if len(reg_data) > 1: raise Exception("Not expected") str_val = reg_data[0] result.add(int(str_val, 16)) return result def parse_veer_dec_tlu_ctl(dec_tlu_ctl_path: Path): with open(dec_tlu_ctl_path) as fd: content = fd.readlines() irqs = _parse_veer_irqs_and_excp(content, 983, 988) excp = _parse_veer_irqs_and_excp(content, 989, 996) return (irqs, excp) # preparing data def inv_dict(data: Dict) -> Dict: result = {} for k, v in data.items(): result[v] = result.get(v, []) + [k] return result def remove_suffix_number(string: str) -> str: return re.sub(r"\d+$", "", string) def count_nonempty(d: Dict) -> int: count = 0 for k, v in d.items(): if v: count += 1 return count if __name__ == "__main__": parser = argparse.ArgumentParser(description="Create VeeR core settings file for riscv-dv") parser.add_argument("riscvdv", help="Path to riscv-dv project") parser.add_argument("veer", help="Path to veer project") args = parser.parse_args() # verify arguments riscvdv_instr_pkg_path = Path(args.riscvdv, RISCV_INSTR_PKG_REL_PATH) if not riscvdv_instr_pkg_path.exists(): raise FileNotFoundError(f"{riscvdv_instr_pkg_path} not found") check_sha256(riscvdv_instr_pkg_path, RISCV_INSTR_PKG_SHA) veer_decode_path = Path(args.veer, VEER_DECODE_REL_PATH) if not veer_decode_path.exists(): raise FileNotFoundError(f"{veer_decode_path} not found") check_sha256(veer_decode_path, VEER_DECODE_SHA) veer_csrdecode_path = Path(args.veer, VEER_CSRDECODE_REL_PATH) if not veer_csrdecode_path.exists(): raise FileNotFoundError(f"{veer_csrdecode_path} not found") check_sha256(veer_csrdecode_path, VEER_CSRDECODE_SHA) veer_dec_tlu_ctrl_path = Path(args.veer, VEER_EL2_DEC_TLU_CTRL_PATH) if not veer_dec_tlu_ctrl_path.exists(): raise FileNotFoundError(f"{veer_dec_tlu_ctrl_path} not found") check_sha256(veer_dec_tlu_ctrl_path, VEER_EL2_DEC_TLU_CTRL_SHA) # parse (rdv_csrs, rdv_ints, rdv_excs, rdv_insn_to_cat) = parse_riscv_instr_pkg(riscvdv_instr_pkg_path) veer_insn: List[str] = parse_veer_decode(veer_decode_path) veer_csrs: Dict[str, int] = parse_veer_csrdecode(veer_csrdecode_path) (veer_ints, veer_excs) = parse_veer_dec_tlu_ctl(veer_dec_tlu_ctrl_path) # adjust data rdv_adj_insn_to_cat = dict(rdv_insn_to_cat) rdv_adj_insn_to_cat["WFI"] = "RV32I" rdv_adj_insn_to_cat["MRET"] = "RV32I" rdv_adj_cat_to_insn: Dict[str, str] = inv_dict(rdv_adj_insn_to_cat) veer_adj_insn = set() for insn in veer_insn: if insn == "rev": insn = "REV8" for x in [ "pack", "grevi", "gorci", "csrw", "csrrwi", "csrrs", "csrrc", "csrrci", "csrrw", ]: if x in insn: insn = remove_suffix_number(insn) for val, new_val in [(".", "_"), ("_rw", ""), ("_ro", "")]: insn = insn.replace(val, new_val) veer_adj_insn.add(insn.upper()) veer_adj_csrs = {int(v.replace(".", "0"), 2): k for k, v in veer_csrs.items()} # prepare data veer_found_insn: Set[str] = {insn for insn in veer_adj_insn if insn in rdv_adj_insn_to_cat} veer_not_found_insn: List[str] = {insn for insn in veer_adj_insn if insn not in rdv_adj_insn_to_cat} veer_found_insn_to_cat: Dict[str, str] = {insn: rdv_adj_insn_to_cat[insn] for insn in veer_found_insn} veer_found_cat_to_insn: Dict[str, str] = inv_dict(veer_found_insn_to_cat) veer_isas: Set[str] = set(veer_found_insn_to_cat.values()) veer_unsupp_cat_to_insn: Dict[str, str] = {} for cat, insns in rdv_adj_cat_to_insn.items(): if cat in veer_found_cat_to_insn: veer_unsupp_cat_to_insn[cat] = set(insns) - set(veer_found_cat_to_insn[cat]) veer_found_csrs: Dict[str, str] = { csr: rdv_csrs[csr] for csr in veer_adj_csrs.keys() if csr in rdv_csrs.keys() } veer_not_found_csrs: Dict[str, str] = { csr: veer_adj_csrs[csr].upper() for csr in (set(veer_adj_csrs.keys() - set(veer_found_csrs.keys()))) } veer_found_ints: Dict[int, str] = {intr: rdv_ints[intr] for intr in veer_ints if intr in rdv_ints} veer_not_found_ints: Set[str] = {intr for intr in veer_ints if intr not in rdv_ints} veer_found_excs: Dict[int, str] = {excp: rdv_excs[excp] for excp in veer_excs if excp in rdv_excs} veer_not_found_excs: Set[str] = {excp for excp in veer_excs if excp not in rdv_excs} # print info print("//-----------------------------------------------------------------------------") print("// Processor feature configuration") print("//-----------------------------------------------------------------------------") print("//") print("parameter int XLEN = 32;") print("parameter satp_mode_t SATP_MODE = BARE;") print("privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE, USER_MODE};") print("") print("// NOTE: To get supported and unsupported instructions compare") print("// riscv-dv/src/riscv_instr_pkg.sv and Cores-VeeR-EL2/design/dec/decode files") print("") print("// Unsupported instructions") print("riscv_instr_name_t unsupported_instr[] = {") cnt = 0 for i, (cat, insns) in enumerate(veer_unsupp_cat_to_insn.items()): if insns: sep = "," if cnt != (count_nonempty(veer_unsupp_cat_to_insn) - 1) else "" print(f" {', '.join(insns)}{sep} // {cat}") cnt += 1 print("};") print() print("// ISA supported by the processor") print("riscv_instr_group_t supported_isa[$] = {") for i, isa in enumerate(veer_isas): sep = "," if i != (len(veer_isas) - 1) else "" print(f" {isa}{sep}") print("};") print() print("// Interrupt mode support") print("mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED};") print("") print("// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is supported") print("int max_interrupt_vector_num = 16;") print("") print("// Physical memory protection support") print("bit support_pmp = 1;") print("") print("// Enhanced physical memory protection support") print("// NOTE: Not supported by VeeR, described in:") print("// https://raw.githubusercontent.com/riscv/riscv-tee/main/Smepmp/Smepmp.pdf") print("bit support_epmp = 0;") print("") print("// Debug mode support") print("bit support_debug_mode = 0;") print("") print("// Support delegate trap to user mode") print("// When implementing UCAUSE, UTVEC, UTVAL, UEPC, USCRATCH, USTATUS, UIE, UIP") print("bit support_umode_trap = 0;") print("") print("// Support sfence.vma instruction") print("bit support_sfence = 0;") print("") print("// Support unaligned load/store") print("bit support_unaligned_load_store = 1'b1;") print("") print("// GPR setting") print("parameter int NUM_FLOAT_GPR = 32;") print("parameter int NUM_GPR = 32;") print("parameter int NUM_VEC_GPR = 32;") print("") print("// ----------------------------------------------------------------------------") print("// Vector extension configuration") print("// ----------------------------------------------------------------------------") print("// Parameter for vector extension") print("parameter int VECTOR_EXTENSION_ENABLE = 0;") print("") print("parameter int VLEN = 512;") print("") print("// Maximum size of a single vector element") print("parameter int ELEN = 32;") print("") print("// Minimum size of a sub-element, which must be at most 8-bits.") print("parameter int SELEN = 8;") print("") print("// Maximum size of a single vector element (encoded in vsew format)") print("parameter int VELEN = int'($ln(ELEN)/$ln(2)) - 3;") print("") print("// Maxium LMUL supported by the core") print("parameter int MAX_LMUL = 8;") print("// ----------------------------------------------------------------------------") print("// Multi-harts configuration") print("// ----------------------------------------------------------------------------") print("") print("// Number of harts") print("parameter int NUM_HARTS = 1;") print("") print("// ----------------------------------------------------------------------------") print("// Previleged CSR implementation") print("// ----------------------------------------------------------------------------") print("") print("// Implemented previlieged CSR list") print("`ifdef DSIM") print("privileged_reg_t implemented_csr[] = {") print("`else") print("const privileged_reg_t implemented_csr[] = {") print("`endif") for i, (addr, name) in enumerate(veer_found_csrs.items()): sep = "," if i != len(veer_found_csrs) - 1 else "" print(f" {name}{sep}") print("};") print("") print("// Implementation-specific custom CSRs") print("// By default all not found registers are put to custom csrs") print("bit [11:0] custom_csr[] = {") for i, (addr, name) in enumerate(veer_not_found_csrs.items()): sep = "," if i != len(veer_not_found_csrs) - 1 else "" print(f" 12'h{addr:X}{sep} // {name}") print("};") print("") print("// ----------------------------------------------------------------------------") print("// Supported interrupt/exception setting, used for functional coverage") print("// ----------------------------------------------------------------------------") print("") print("`ifdef DSIM") print("interrupt_cause_t implemented_interrupt[] = {") print("`else") print("const interrupt_cause_t implemented_interrupt[] = {") print("`endif") for i, (intr, name) in enumerate(veer_found_ints.items()): sep = "," if i != len(veer_found_ints) - 1 else "" print(f" {name}{sep}") for i, intr in enumerate(veer_not_found_ints): if intr in (list(range(24, 32)) + list(range(48, 64))): print(f" //{hex(intr)} custom interrupt used") elif intr in ([14] + list(range(16, 20)) + list(range(32, 48))): print(f" //{hex(intr)} reserved interrupt used") else: print(f" //{hex(intr)} not supported") print("};") print("") print("`ifdef DSIM") print("exception_cause_t implemented_exception[] = {") print("`else") print("const exception_cause_t implemented_exception[] = {") for i, (exc, name) in enumerate(veer_found_excs.items()): sep = "," if i != len(veer_found_excs) - 1 else "" print(f" {name}{sep}") for i, exc in enumerate(veer_not_found_excs): print(f" //{hex(exc)} not supported") print("};") print("`endif") ================================================ FILE: tools/riscv-dv/riscv_core_setting.sv ================================================ //----------------------------------------------------------------------------- // Processor feature configuration //----------------------------------------------------------------------------- // parameter int XLEN = 32; parameter satp_mode_t SATP_MODE = BARE; privileged_mode_t supported_privileged_mode[] = {MACHINE_MODE, USER_MODE}; // NOTE: To get supported and unsupported instructions compare // riscv-dv/src/riscv_instr_pkg.sv and Cores-VeeR-EL2/design/dec/decode files // Unsupported instructions riscv_instr_name_t unsupported_instr[] = { NOP, // RV32I CLZ, // RV32ZBB SROI, CMIX, FSRI, FSR, CMOV, SRO, SLO, FSL, SLOI, // RV32B // FIXME: As of date, the decision on which bitmanip extensions should go // into the `B` collection is not yet ratified. // // To stay on the safe side, let's assume here that *all of them* are // enabled by the `B` extension collection. CRC32C_B, CRC32C_H, CRC32C_W, CRC32_B, CRC32_H, CRC32_W, // RV32ZBR GORC, GORCI, GREV, GREVI, SHFL, SHFLI, UNSHFL, UNSHFLI, // RV32ZBP BCOMPRESS, BDECOMPRESS, // RV32ZBE BFP, // RV32ZBF XPERM_B, XPERM_H, XPERM_N // RV32ZBP }; // ISA supported by the processor riscv_instr_group_t supported_isa[$] = { RV32I, RV32M, RV32C, RV32B, RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS }; // Interrupt mode support mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED}; // The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is supported int max_interrupt_vector_num = 16; // Physical memory protection support bit support_pmp = 1; // Enhanced physical memory protection support // NOTE: Not supported by VeeR, described in: // https://raw.githubusercontent.com/riscv/riscv-tee/main/Smepmp/Smepmp.pdf bit support_epmp = 0; // Debug mode support bit support_debug_mode = 0; // Support delegate trap to user mode // When implementing UCAUSE, UTVEC, UTVAL, UEPC, USCRATCH, USTATUS, UIE, UIP bit support_umode_trap = 0; // Support sfence.vma instruction bit support_sfence = 0; // Support unaligned load/store bit support_unaligned_load_store = 1'b1; // GPR setting parameter int NUM_FLOAT_GPR = 32; parameter int NUM_GPR = 32; parameter int NUM_VEC_GPR = 32; // ---------------------------------------------------------------------------- // Vector extension configuration // ---------------------------------------------------------------------------- // Parameter for vector extension parameter int VECTOR_EXTENSION_ENABLE = 0; parameter int VLEN = 512; // Maximum size of a single vector element parameter int ELEN = 32; // Minimum size of a sub-element, which must be at most 8-bits. parameter int SELEN = 8; // Maximum size of a single vector element (encoded in vsew format) parameter int VELEN = int'($ln(ELEN)/$ln(2)) - 3; // Maxium LMUL supported by the core parameter int MAX_LMUL = 8; // ---------------------------------------------------------------------------- // Multi-harts configuration // ---------------------------------------------------------------------------- // Number of harts parameter int NUM_HARTS = 1; // ---------------------------------------------------------------------------- // Previleged CSR implementation // ---------------------------------------------------------------------------- // Implemented previlieged CSR list `ifdef DSIM privileged_reg_t implemented_csr[] = { `else const privileged_reg_t implemented_csr[] = { `endif MARCHID, MIMPID, MHARTID, MSTATUS, MTVEC, MIP, MIE, MCYCLE, MCYCLEH, MINSTRET, MINSTRETH, MSCRATCH, MEPC, MCAUSE, MTVAL, DCSR, DPC, TSELECT, TDATA1, TDATA2, MHPMCOUNTER3, MHPMCOUNTER4, MHPMCOUNTER5, MHPMCOUNTER6, MHPMCOUNTER3H, MHPMCOUNTER4H, MHPMCOUNTER5H, MHPMCOUNTER6H, MHPMEVENT3, MHPMEVENT4, MHPMEVENT5, MHPMEVENT6, MHPMCOUNTER7, MHPMCOUNTER8, MHPMCOUNTER16, MHPMCOUNTER7H, MHPMCOUNTER8H, MHPMCOUNTER16H, MHPMEVENT7, MHPMEVENT8, MHPMEVENT16, MCOUNTINHIBIT, MSECCFG, PMPCFG0, PMPCFG1, PMPCFG2, PMPCFG3, PMPADDR0, PMPADDR1, PMPADDR2, PMPADDR3, PMPADDR4, PMPADDR5, PMPADDR6, PMPADDR7, PMPADDR8, PMPADDR9, PMPADDR10, PMPADDR11, PMPADDR12, PMPADDR13, PMPADDR14, PMPADDR15 }; // Implementation-specific custom CSRs // By default all not found registers are put to custom csrs bit [11:0] custom_csr[] = { 12'h3D0, // CSR_PMPADDR32 12'h7C0, // CSR_MRAC 12'hBC0, // CSR_MDEAU 12'hFC0, // CSR_MDSEAC 12'h7C2, // CSR_MCPC 12'h7C4, // CSR_DMST 12'h3C0, // CSR_PMPADDR16 12'h7C6, // CSR_MPMC 12'hBC8, // CSR_MEIVT 12'hFC8, // CSR_MEIHAP 12'hBC9, // CSR_MEIPT 12'hBCA, // CSR_MEICPCT 12'hBCC, // CSR_MEICURPL 12'hBCB, // CSR_MEICIDPL 12'h7CE, // CSR_MFDHT 12'h7CF, // CSR_MFDHS 12'h7C8, // CSR_DICAWICS 12'h7CC, // CSR_DICAD0H 12'h7C9, // CSR_DICAD0 12'h7CA, // CSR_DICAD1 12'h7CB, // CSR_DICAGO 12'h7D3, // CSR_MITB0 12'h7D4, // CSR_MITCTL0 12'h7D2, // CSR_MITCNT0 12'h7D6, // CSR_MITB1 12'h7D7, // CSR_MITCTL1 12'h7D5, // CSR_MITCNT1 12'h3E0, // CSR_PMPADDR48 12'h7F0, // CSR_MICECT 12'h7F1, // CSR_MICCMECT 12'h7F2, // CSR_MDCCMECT 12'h7F8, // CSR_MCGC 12'h7F9, // CSR_MFDC 12'h7FF // CSR_MSCAUSE }; // ---------------------------------------------------------------------------- // Supported interrupt/exception setting, used for functional coverage // ---------------------------------------------------------------------------- `ifdef DSIM interrupt_cause_t implemented_interrupt[] = { `else const interrupt_cause_t implemented_interrupt[] = { `endif M_SOFTWARE_INTR, M_TIMER_INTR, M_EXTERNAL_INTR //0x1c custom interrupt used //0x1d custom interrupt used //0x1e custom interrupt used }; `ifdef DSIM exception_cause_t implemented_exception[] = { `else const exception_cause_t implemented_exception[] = { INSTRUCTION_ACCESS_FAULT, BREAKPOINT, LOAD_ADDRESS_MISALIGNED, LOAD_ACCESS_FAULT, STORE_AMO_ADDRESS_MISALIGNED, STORE_AMO_ACCESS_FAULT, ECALL_MMODE }; `endif ================================================ FILE: tools/riscv-dv/testlist.yaml ================================================ - import: /target/rv32imc/testlist.yaml - test: riscv_pmp_disable_all_regions_test_veer desc: > Disable all permissions from PMP regions, randomize the boot mode, and randomize mstatus.mprv. Expect that all appropriate faults are taken, and that the core finishes executing successfully. iterations: 50 gen_test: riscv_rand_instr_test gen_opts: > +instr_cnt=6000 +set_mstatus_mprv=1 +pmp_max_offset=00024000 +pmp_region_1=L:1,X:0,W:0,R:0 +pmp_region_2=L:1,X:0,W:0,R:0 +pmp_region_3=L:1,X:0,W:0,R:0 +pmp_region_4=L:1,X:0,W:0,R:0 +pmp_region_5=L:1,X:0,W:0,R:0 +pmp_region_6=L:1,X:0,W:0,R:0 +pmp_region_7=L:1,X:0,W:0,R:0 +pmp_region_8=L:1,X:0,W:0,R:0 +pmp_region_9=L:1,X:0,W:0,R:0 +pmp_region_10=L:1,X:0,W:0,R:0 +pmp_region_11=L:1,X:0,W:0,R:0 +pmp_region_12=L:1,X:0,W:0,R:0 +pmp_region_13=L:1,X:0,W:0,R:0 +pmp_region_14=L:1,X:0,W:0,R:0 +pmp_region_15=L:1,X:0,W:0,R:0 +enable_write_pmp_csr=1 +mseccfg=MML:0,MMWP:0,RLB:0 rtl_test: core_base_test - test: riscv_pmp_out_of_bounds_test_veer desc: > Default PMP settings - enable all regions with full permissions. Randomize mstatus.mprv and the boot mode. Insert streams of memory instructions that access addresses out of PMP boundaries. iterations: 50 gen_test: riscv_rand_instr_test gen_opts: > +instr_cnt=6000 +set_mstatus_mprv=1 +pmp_max_offset=00024000 +enable_write_pmp_csr=1 +directed_instr_0=veer_load_store_rand_addr_instr_stream,50 +mseccfg=MML:0,MMWP:0,RLB:0 rtl_test: core_base_test sim_opts: > +is_double_fault_detected_fatal=0 +enable_bad_intg_on_uninit_access=0 - test: riscv_pmp_full_random_test_veer desc: > Completely randomize the boot mode, mstatus.mprv, and all PMP configuration, and allow PMP regions to overlap. A large number of iterations will be required since this introduces a huge state space of configurations. Some configurations result in very slow execution as every instruction ends up generating a fault. As this is still a useful test a short timeout with pass on timeout is enabled. iterations: 600 gen_test: riscv_rand_instr_test gen_opts: > +instr_cnt=6000 +set_mstatus_mprv=1 +pmp_randomize=1 +pmp_max_offset=00040000 +pmp_allow_illegal_tor=1 +directed_instr_0=riscv_load_store_rand_instr_stream,40 +directed_instr_1=riscv_load_store_hazard_instr_stream,40 +directed_instr_2=veer_load_store_rand_addr_instr_stream,40 +enable_unaligned_load_store=1 sim_opts: > +is_double_fault_detected_fatal=0 +is_timeout_s_fatal=0 +enable_bad_intg_on_uninit_access=0 rtl_test: core_base_test - test: riscv_pmp_region_exec_test_veer desc: > A more specialised pmp_full_random_test that attempts to make regions executable whilst MML is set. iterations: 20 gen_test: riscv_rand_instr_test gen_opts: > +instr_cnt=6000 +set_mstatus_mprv=1 +pmp_randomize=1 +pmp_max_offset=00040000 +pmp_allow_illegal_tor=1 +directed_instr_0=riscv_load_store_rand_instr_stream,40 +enable_unaligned_load_store=1 +boot_mode=m +mseccfg=MML:1,MMWP:0,RLB:0 sim_opts: > +is_double_fault_detected_fatal=0 +is_timeout_s_fatal=0 +enable_bad_intg_on_uninit_access=0 rtl_test: core_base_test - test: riscv_bitmanip_full_test_veer desc: > Random instruction test with supported B extension instructions in full configuration. iterations: 10 gen_test: riscv_rand_instr_test gen_opts: > +enable_zba_extension=1 +enable_zbb_extension=1 +enable_zbc_extension=1 +enable_zbs_extension=1 +enable_b_extension=1 +enable_bitmanip_groups=zbe,zbf,zbp,zbr,zbt rtl_test: core_base_test - test: riscv_bitmanip_balanced_test_veer desc: > Random instruction test with supported B extension instructions in balanced configuration. iterations: 10 gen_test: riscv_rand_instr_test gen_opts: > +enable_zba_extension=1 +enable_zbb_extension=1 +enable_zbs_extension=1 +enable_b_extension=1 +enable_bitmanip_groups=zbf,zbt - test: riscv_user_mode_rand_test desc: > User mode random instruction test iterations: 100 gen_test: riscv_instr_base_test gen_opts: > +instr_cnt=10000 +boot_mode=u rtl_test: core_base_test ================================================ FILE: tools/riscv-dv/user_extension.svh ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. `include "veer_directed_instr_lib.sv" ================================================ FILE: tools/riscv-dv/veer_directed_instr_lib.sv ================================================ // SPDX-License-Identifier: Apache-2.0 // Copyright (c) 2024 Antmicro // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. class veer_load_store_rand_addr_instr_stream extends riscv_load_store_rand_addr_instr_stream; // Avoid writing in higher memory regions constraint addr_offset_veer_c {addr_offset[XLEN-1:30] == 0;} `uvm_object_utils(veer_load_store_rand_addr_instr_stream) `uvm_object_new endclass ================================================ FILE: tools/riscv-dv/veer_log_to_trace_csv.py ================================================ #!/usr/bin/env python3 import argparse import re from riscv_trace_csv import RiscvInstructionTraceEntry, RiscvInstructionTraceCsv # ============================================================================= INSTR_RE = re.compile(r"^\s*(?P[0-9]+)\s+:\s+#(?P[0-9]+)\s+0\s+" r"(?P[0-9a-f]+)\s+(?P[0-9a-f]+)\s+" r"((?P[^=;]+)=(?P[0-9a-f]+))?\s+" r"((?P[^=;]+)=(?P[0-9a-f]+))?" r"\s+;\s+(?P.*)") NB_RE = re.compile(r"^\s*(?P[0-9]+)\s+:\s+" r"(?P[^=;]+)=(?P[0-9a-f]+)" r"\s+;\s+(?P(nbL|nbD))") LD_MNEMONICS = ["lb", "lbu", "lh", "lhu", "lw", "c.lw", "c.lwsp"] DIV_MNEMONICS = ["div", "divu", "rem", "remu"] # ============================================================================= def parse_log(file_name): """ Parses VeeR-EL2 execution log generated by HDL simulation. The core is in-order however, due to pipelined implementation certain instructions may have an effect in different clock cycle than they are executed. The testbench trace handes this by emitting special "nbL" and "nbD" entries which need to be correlated with the actual instruction. Most of the logic of this parser does exactly that. Every trace entry is put into a temporary queue. Whenever a "nbL"/"nbD" is encountered, the queue is searched for a matching counterpart. This happens in the opposite way as well eg. when a "div" is encountered the queue is searched for "nbD" Once an entry is found, relevant data is filled in. Entires are poped of the queue only when they contain all the information for the complete trace. """ # Read the log with open(file_name, "r") as fp: lines = fp.readlines() data = [] queue = [] for line in lines: line = line.strip() # Instruction match = INSTR_RE.match(line) if match is not None: groups = match.groupdict() gpr = None csr = None if groups["reg"] and groups["val"]: gpr = ("{}:{}".format(groups["reg"], groups["val"])) if groups["csr"] and groups["csr_val"]: csr = ("{}:{}".format(groups["csr"], groups["csr_val"])) fields = groups["mnemonic"].split() mnemonic = fields[0] operands = fields[1].split(",") if len(fields) > 1 else [] entry = None # Stop on ecall if mnemonic == "ecall": break # Delayed effect, search the queue if gpr is None and mnemonic in LD_MNEMONICS + DIV_MNEMONICS: # Skip if targets x0 (zero) which makes no sense if operands[0] == "zero": continue for ent in reversed(queue): if (ent.operand == "nbL" and mnemonic in LD_MNEMONICS) or \ (ent.operand == "nbD" and mnemonic in DIV_MNEMONICS): assert len(operands), line assert len(ent.gpr), ent.get_trace_string() reg, val = ent.gpr[0].split(":") # FIXME: Assuming single GPR if reg == operands[0]: entry = ent break # Enqueue or not enqueue = entry is None and (gpr is not None or mnemonic in \ LD_MNEMONICS + DIV_MNEMONICS) # Entry not found in the queue, create it if not entry: entry = RiscvInstructionTraceEntry() # Fill data entry.pc = groups["pc"] entry.binary = groups["opc"] entry.operand = groups["mnemonic"] entry.mode = "0" # TODO # Append GPR if any if gpr: entry.gpr.append(gpr) if csr: entry.csr.append(csr) # Enqueue if enqueue: queue.append(entry) # nbL / nbD match = NB_RE.match(line) if match is not None: groups = match.groupdict() assert groups["reg"] and groups["val"], line gpr = ("{}:{}".format(groups["reg"], groups["val"])) # Skip if targets x0 (zero) which makes no sense if groups["reg"] == "zero": continue # Find an existing nbL/nbD entry in the queue. Match destination GPR for entry in reversed(queue): fields = entry.operand.split() mnemonic = fields[0] operands = fields[1].split(",") if len(fields) > 1 else [] if (groups["mnemonic"] == "nbL" and mnemonic in LD_MNEMONICS) or \ (groups["mnemonic"] == "nbD" and mnemonic in DIV_MNEMONICS): assert len(operands), entry if groups["reg"] == operands[0]: entry.gpr.append(gpr) break # Add a new entry else: entry = RiscvInstructionTraceEntry() entry.operand = groups["mnemonic"] entry.gpr.append(gpr) queue.append(entry) # Dequeue entries that have all they need. Stop at the first one which # is missing something. while len(queue): entry = queue[0] # Cannot dequeue, break if not entry.pc or not entry.gpr: break # Pop data.append(entry) queue = queue[1:] # Safeguard if len(queue) >= 1000: print("ERROR: Malformed trace, the queue grew too much") for entry in reversed(queue): print("", entry.get_trace_string()) assert False return data def write_csv(file_name, data): """ Writes the trace to CSV """ with open(file_name, "w") as fp: writer = RiscvInstructionTraceCsv(fp) writer.start_new_trace() for entry in data: writer.write_trace_entry(entry) # ============================================================================= def main(): parser = argparse.ArgumentParser() parser.add_argument( "--log", type=str, required=True, help="HDL simulation trace log" ) parser.add_argument( "--csv", type=str, required=True, help="Output CSV file" ) args = parser.parse_args() # Parse log data = parse_log(args.log) # Write CSV write_csv(args.csv, data) if __name__ == "__main__": main() ================================================ FILE: tools/smalldiv ================================================ #!/usr/bin/perl use Getopt::Long; use integer; $helpusage = "placeholder"; GetOptions ('len=s' => \$len, 'num=s' => \$num, 'den=s' => \$den, 'skip' => \$skip) || die("$helpusage"); if (!defined($len)) { $len=8; } $LEN=$len; $n=d2b($num); # numerator - quotient $m=d2b($den); # denominator - divisor printf(".i 8\n"); printf(".o 4\n"); printf(".ilb q_ff[3] q_ff[2] q_ff[1] q_ff[0] m_ff[3] m_ff[2] m_ff[1] m_ff[0]\n"); printf(".ob smallnum[3] smallnum[2] smallnum[1] smallnum[0]\n"); printf(".type fr\n"); for ($q=0; $q<16; $q++) { for ($m=0; $m<16; $m++) { if ($m==0) { next; } $result=int($q/$m); printf("%s %s %s\n",d2bl($q,4),d2bl($m,4),d2bl($result,4)); } } exit; #$LEN=length($n); $a="0"x$LEN; $q=$n; #printf("n=%s, m=%s\n",$n,$m); #printf("a=%s, q=%s\n",$a,$q); for ($i=1; $i<=$LEN; $i++) { #printf("iteration $n:\n"); printf("$i: a=%s q=%s\n",$a,$q); $signa = substr($a,0,1); $a = substr($a.$q,1,$LEN); # new a with q shifted in if ($signa==0) { $a=b2d($a)-b2d($m); } else { $a=b2d($a)+b2d($m); } $a=d2b($a); $signa = substr($a,0,1); if ($signa==0) { $q=substr($q,1,$LEN-1)."1"; } else { $q=substr($q,1,$LEN-1)."0"; } } #printf("a=$a\n"); $signa = substr($a,0,1); if ($signa==1 && !defined($skip)) { printf("correction:\n"); $a=b2d($a)+b2d($m); $a=d2b($a); } #printf("a=$a\n"); printf("%d / %d = %d R %d ",b2d($n),b2d($m),b2d($q),b2d($a)); if ($a eq $n) { printf("-> remainder equal numerator\n"); } else { printf("\n"); } sub b2d { my ($v) = @_; $v = oct("0b" . $v); return($v); } sub d2b { my ($v) = @_; my $repeat; $v = sprintf "%b",$v; if (length($v)<$LEN) { $repeat=$LEN-length($v); $v="0"x$repeat.$v; } elsif (length($v)>$LEN) { $v=substr($v,length($v)-$LEN,$LEN); } return($v); } sub d2bl { my ($v,$LEN) = @_; my $repeat; $v = sprintf "%b",$v; if (length($v)<$LEN) { $repeat=$LEN-length($v); $v="0"x$repeat.$v; } elsif (length($v)>$LEN) { $v=substr($v,length($v)-$LEN,$LEN); } return($v); } ================================================ FILE: tools/unrollforverilator ================================================ #!/usr/bin/perl #use strict; #use warnings; my $RV_ROOT = $ENV{RV_ROOT}; my $TOTAL_INT=$ARGV[0]; print "// argv=".$ARGV[0]."\n"; my $NUM_LEVELS; if($TOTAL_INT==2){$NUM_LEVELS=1;} elsif ($TOTAL_INT==4){$NUM_LEVELS=2;} elsif ($TOTAL_INT==8){$NUM_LEVELS=3;} elsif ($TOTAL_INT==16){$NUM_LEVELS=4;} elsif ($TOTAL_INT==32){$NUM_LEVELS=5;} elsif ($TOTAL_INT==64){$NUM_LEVELS=6;} elsif ($TOTAL_INT==128){$NUM_LEVELS=7;} elsif ($TOTAL_INT==256){$NUM_LEVELS=8;} elsif ($TOTAL_INT==512){$NUM_LEVELS=9;} elsif ($TOTAL_INT==1024){$NUM_LEVELS=10;} else {$NUM_LEVELS=int(log($TOTAL_INT)/log(2))+1;} print ("// TOTAL_INT=".$TOTAL_INT." NUM_LEVELS=".$NUM_LEVELS."\n"); $next_level = 1; print ("`ifdef RV_PIC_2CYCLE\n"); if($TOTAL_INT > 2){ print ("// LEVEL0\n"); print ("logic [TOTAL_INT+2:0] [INTPRIORITY_BITS-1:0] level_intpend_w_prior_en_".$next_level.";\n"); print ("logic [TOTAL_INT+2:0] [ID_BITS-1:0] level_intpend_id_".$next_level.";\n"); print (" for (m=0; m<=(TOTAL_INT)/(2**(".$next_level.")) ; m++) begin : COMPARE0\n"); print (" if ( m == (TOTAL_INT)/(2**(".$next_level."))) begin \n"); print (" assign level_intpend_w_prior_en_".$next_level."[m+1] = '0 ;\n"); print (" assign level_intpend_id_".$next_level."[m+1] = '0 ;\n"); print (" end\n"); print (" cmp_and_mux #(\n"); print (" .ID_BITS(ID_BITS),\n"); print (" .INTPRIORITY_BITS(INTPRIORITY_BITS)) cmp_l".$next_level." (\n"); print (" .a_id(level_intpend_id[0][2*m]),\n"); print (" .a_priority(level_intpend_w_prior_en[0][2*m]),\n"); print (" .b_id(level_intpend_id[0][2*m+1]),\n"); print (" .b_priority(level_intpend_w_prior_en[0][2*m+1]),\n"); print (" .out_id(level_intpend_id_".$next_level."[m]),\n"); print (" .out_priority(level_intpend_w_prior_en_".$next_level."[m])) ;\n"); print (" \n"); print (" end\n\n"); for (my $l=1; $l> i) & 1 def _prevent_11_pairs(value): new_value = 0 for i in reversed(range(0, 31, 2)): new_value = new_value << 2 b0 = get_bit(value, i) b1 = get_bit(value, i + 1) new_value |= (b1 << 1) | (b0 & (not b1)) return new_value def _mhpme_zero_event(value): return ( (value > 516) | ((value < 512) & (value > 56)) | ((value < 54) & (value > 50)) | (value == 29) | (value == 33) ) def _m_ect(value): if ((value >> 27) & 0x1F) > 26: value = value & 0x07FFFFFF value = value | (26 << 27) return value def _dicawics(value): value = value & 0x1FFFFFF value = value & ~(1 << 23) value = value & ~(1 << 22) value = value & ~(1 << 19) value = value & ~(1 << 18) value = value & ~(1 << 17) value = value & ~(1 << 2) value = value & ~(1 << 1) value = value & ~(1 << 0) return value def _dcsr(value): value = (value & 0xFFFF) | (0x4 << 28) value = (value & 0xFFFFFFFC) | 0x3 value = value & ~(1 << 14) # reserved value = value & ~(1 << 13) # ebreaks (0 for VeeR-EL2) value = value & ~(1 << 12) # ebreaku (0 for VeeR-EL2) value = value & ~(1 << 9) # stoptime (0 for VeeR-EL2) value = value & ~(1 << 8) # reserved value = (value & ~(1 << 7)) | (1 << 7) value = (value & ~(1 << 6)) | (1 << 6) value = value & ~(1 << 5) # reserved value = value & ~(1 << 4) # reserved value = value & ~(1 << 3) # reserved return value # Dbus Error Address Unlock register MDEAU = CSR(0xBC0) # Dbus Store Error Address Capture register MDSEAC = CSR(0xFC0) MEICPCT = CSR(0xBCA) MEIVT = CSR(0xBC8) # MTSEL (R/W) # [1:0] : Trigger select : 00, 01, 10 are data/address triggers. 11 is inst count MTSEL = CSR(0x7A0) # MTDATA1 (R/W) # [31:0] : Trigger Data 1 MTDATA1 = CSR(0x7A1) # MTDATA2 (R/W) # [31:0] : Trigger Data 2 MTDATA2 = CSR(0x7A2) # External Interrupt Priority Threshold MEIPT = CSR(0xBC9, lambda _: _ & 0xF) # [31:2] BASE : Trap vector base address # [1] - Reserved, not implemented, reads zero # [0] MODE : 0 = Direct, 1 = Asyncs MTVEC = CSR(0x305, lambda _: _ & 0xFFFFFFFD) # Region Access Control Register, 16 regions MRAC = CSR(0x7C0, _prevent_11_pairs) MCOUNTINHIBIT = CSR(0x320, lambda _: _ & 0x7D) MFDHT = CSR(0x7CE, lambda _: _ & 0x3F) MEICURPL = CSR(0xBCC, lambda _: _ & 0xF) MFDC = CSR(0xBCC, lambda _: _ & 0x71FBF) # performance counters MHPMC3 = CSR(0xB03) MHPMC3H = CSR(0xB83) MHPMC4 = CSR(0xB04) MHPMC4H = CSR(0xB84) MHPMC5 = CSR(0xB05) MHPMC5H = CSR(0xB85) MHPMC6 = CSR(0xB06) MHPMC6H = CSR(0xB86) MINSTRETL = CSR(0xB02) MINSTRETH = CSR(0xB82) MCYCLEL = CSR(0xB00) MCYCLEH = CSR(0xB80) # hardware performance monitors MHPME3 = CSR(0x323, lambda x: 0 if _mhpme_zero_event(x) else x) MHPME4 = CSR(0x324, lambda x: 0 if _mhpme_zero_event(x) else x) MHPME5 = CSR(0x325, lambda x: 0 if _mhpme_zero_event(x) else x) MHPME6 = CSR(0x326, lambda x: 0 if _mhpme_zero_event(x) else x) MICECT = CSR(0x7F0, _m_ect) MICCMECT = CSR(0x7F1, _m_ect) MDCCMECT = CSR(0x7F2, _m_ect) # debug mode CSRs DICAD0 = CSR(0x7C9) DICAD0H = CSR(0x7CC) DICAD1 = CSR(0x7CA) DICAWICS = CSR(0x7C8, _dicawics) DPC = CSR(0x7B1, lambda _: _ & ~(0x1)) DCSR = CSR(0x7B0, _dcsr) # upper 4 bits hardcoded to 0x4 MEICIDPL = CSR(0xBCB, lambda _: _ & 0xF) ================================================ FILE: verification/block/common/utils.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import logging from collections.abc import Callable from scipy.stats import binom # ============================================================================== def collect_signals(signals, uut, obj, uut_prefix="", obj_prefix="", signal_map=None): """ Collects signal objects from UUT and attaches them to the given object. Optionally UUT signals can be prefixed with the uut_prefix and object signals with the obj_prefix. If signal_map is given it should be a dict mapping signal names to actual UUT signal names. """ for sig in signals: if signal_map is not None: uut_sig = signal_map.get(sig, uut_prefix + sig) else: uut_sig = uut_prefix + sig obj_sig = obj_prefix + sig if hasattr(uut, uut_sig): s = getattr(uut, uut_sig) else: s = None logging.error("Module {} does not have a signal '{}'".format(str(uut), sig)) setattr(obj, obj_sig, s) def collect_bytes(data, strb=None): """ Collects data bytes asserted on a data bus. Uses the strb value to determine which octets are valid. Both data and strb must be cocotb signals. strb can be None. """ if strb is not None: assert len(data) == 8 * len(strb) res = [] for i in range(len(data) // 8): if strb is None or strb.value & (1 << i): dat = (int(data.value) >> (8 * i)) & 0xFF res.append(dat) return bytes(res) def smallest_number_of_trials(p: float, k: int, j: float): """ This function is used to calculate the minimum number of clock cycles that need to pass for an event to be successful given the probability of its conditions occurring. Example: Let module under test enter into a busy state with probability `p`. For an event A to occur the module must not be in the busy state. Then, n = smallest_number_of_trials(p, 1, 99.9) is the smallest number of clock cycles that need to pass for there being 99.9% chance that at least one event A occurs in this n-cycle period. (see verification/block/dma) Based on https://math.stackexchange.com/a/4776687. Returns the smallest n such that P(X >= k) >= j / 100, where X is Binomial(n, p). """ def function_bisect(f: Callable[[int], float], target: float) -> float: """ f is an increasing function from the nonnegative integers to floats. Returns the smallest x such that f(x) >= target. WARNING: This loops forever if there is no x for which f(x) >= target. """ lower_lim = 0 if f(lower_lim) >= target: return lower_lim upper_lim = 2 while f(upper_lim) < target: upper_lim *= 2 while upper_lim - lower_lim >= 2: mid = (lower_lim + upper_lim) // 2 if f(mid) >= target: upper_lim = mid elif f(mid) < target: lower_lim = mid return upper_lim def prob_X_ge_k(n): return 1 - binom.cdf(k - 1, n, p) return function_bisect(prob_X_ge_k, j / 100) ================================================ FILE: verification/block/common.mk ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 $(info $(shell cocotb-config --makefiles)) TOPLEVEL_LANG = verilog SIM ?= verilator WAVES ?= 1 # Paths CURDIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) CFGDIR := $(abspath $(CURDIR)/snapshots/default) CONFIG := $(abspath $(CURDIR)/../../configs) # Set pythonpath so that tests can access common modules export PYTHONPATH := $(CURDIR)/common # Common sources COMMON_SOURCES = $(CFGDIR)/common_defines.vh COMMON_SOURCES += $(CFGDIR)/el2_pdef.vh COMMON_SOURCES += $(SRCDIR)/include/el2_def.sv COMMON_SOURCES += $(SRCDIR)/lib/beh_lib.sv VERILOG_SOURCES := $(COMMON_SOURCES) $(VERILOG_SOURCES) # Coverage reporting COVERAGE_TYPE ?= "" ifeq ("$(COVERAGE_TYPE)", "all") VERILATOR_COVERAGE = --coverage else ifeq ("$(COVERAGE_TYPE)", "branch") VERILATOR_COVERAGE = --coverage-line else ifeq ("$(COVERAGE_TYPE)", "toggle") VERILATOR_COVERAGE = --coverage-toggle else ifeq ("$(COVERAGE_TYPE)", "functional") VERILATOR_COVERAGE = --coverage-user else VERILATOR_COVERAGE = "" endif ifeq ($(SIM), verilator) COMPILE_ARGS += --coverage-max-width 20000 COMPILE_ARGS += --timing COMPILE_ARGS += -Wall COMPILE_ARGS += $(CURDIR)/config.vlt EXTRA_ARGS += --trace --trace-structs EXTRA_ARGS += $(VERILATOR_COVERAGE) EXTRA_ARGS += -I$(CFGDIR) -Wno-DECLFILENAME # Include test specific Verilator config if it exists ifneq ("$(wildcard $(TEST_DIR)/config.vlt)","") COMPILE_ARGS += $(TEST_DIR)/config.vlt endif PARALLEL_THREADS := $(shell echo $$(( $(shell nproc) - 1 ))) BUILD_ARGS += -j $(PARALLEL_THREADS) else ifeq ($(SIM), vcs) ifneq ($(CM_FILE),) EXTRA_ARGS += -cm_hier $(TEST_DIR)/$(CM_FILE) endif EXTRA_ARGS += +incdir+$(CFGDIR) +incdir+$(SRCDIR)/include -assert svaext -cm line+cond+fsm+tgl+branch +vcs+lic+wait endif # Produces verilog.dump VCD file ifneq ($(VCS_DEBUG),) EXTRA_ARGS = +vcs+dumpon +vcs+dumpvars endif COCOTB_HDL_TIMEUNIT = 1ns COCOTB_HDL_TIMEPRECISION = 10ps # Build directory ifeq ($(COVERAGE_TYPE),"") SIM_BUILD ?= sim-build else SIM_BUILD ?= sim-build-$(COVERAGE_TYPE) endif include $(shell cocotb-config --makefiles)/Makefile.sim ifeq ($(PMP_TEST),) EXTRA_CONFIG_OPTS = "" else EXTRA_CONFIG_OPTS = "-set=pmp_entries=64" endif ifneq ($(DEC_TEST),) EXTRA_CONFIG_OPTS += "-set=fast_interrupt_redirect=0" endif # Rules for generating VeeR config $(CFGDIR)/common_defines.vh: cd $(CURDIR) && $(CONFIG)/veer.config -fpga_optimize=0 $(EXTRA_CONFIG_OPTS) $(EXTRA_VEER_CONFIG) ================================================ FILE: verification/block/config.vlt ================================================ `verilator_config // Unnamed blocks do not influence logic lint_off -rule GENUNNAMED // Unconnected IC memory output pins lint_off -rule PINCONNECTEMPTY -file "*/el2_ifu_ic_mem.sv" // These require revisit to remove multiple definitions of variables with same names lint_off -rule VARHIDDEN -file "*/axi4_to_ahb.sv" lint_off -rule VARHIDDEN -file "*/el2_ifu_bp_ctl.sv" lint_off -rule VARHIDDEN -file "*/el2_ifu_mem_ctl.sv" lint_off -rule VARHIDDEN -file "*/el2_exu_alu_ctl.sv" lint_off -rule VARHIDDEN -file "*/el2_pic_ctrl.sv" // Width related warning require explicit type casting lint_off -rule WIDTHTRUNC -file "*/ahb_to_axi4.sv" lint_off -rule WIDTHTRUNC -file "*/axi4_to_ahb.sv" lint_off -rule WIDTHTRUNC -file "*/el2_dma_ctrl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_ifu_ifc_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_ifu_bp_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_ifu_aln_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_dec_decode_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_dec_ib_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_dec_tlu_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_dec_trigger.sv" lint_off -rule WIDTHTRUNC -file "*/el2_lib.sv" lint_off -rule WIDTHTRUNC -file "*/beh_lib.sv" lint_off -rule WIDTHTRUNC -file "*/el2_lsu_bus_buffer.sv" lint_off -rule WIDTHTRUNC -file "*/el2_dec_pmp_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_lsu_addrcheck.sv" lint_off -rule WIDTHTRUNC -file "*/el2_lsu_dccm_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_lsu_dccm_mem.sv" lint_off -rule WIDTHTRUNC -file "*/el2_lsu_trigger.sv" lint_off -rule WIDTHTRUNC -file "*/el2_ifu_iccm_mem.sv" lint_off -rule WIDTHTRUNC -file "*/el2_ifu_mem_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_exu.sv" lint_off -rule WIDTHTRUNC -file "*/el2_exu_alu_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_exu_div_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_exu_mul_ctl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_dbg.sv" lint_off -rule WIDTHTRUNC -file "*/el2_pic_ctrl.sv" lint_off -rule WIDTHTRUNC -file "*/el2_pmp.sv" lint_off -rule WIDTHTRUNC -file "*/el2_mem_if.sv" lint_off -rule WIDTHEXPAND -file "*/el2_exu.sv" lint_off -rule WIDTHEXPAND -file "*/el2_pic_ctrl.sv" lint_off -rule WIDTHEXPAND -file "*/el2_ifu_bp_ctl.sv" lint_off -rule WIDTHEXPAND -file "*/el2_ifu_mem_ctl.sv" lint_off -rule WIDTHEXPAND -file "*/el2_ifu_iccm_mem.sv" lint_off -rule WIDTHEXPAND -file "*/el2_lsu_addrcheck.sv" lint_off -rule WIDTHEXPAND -file "*/el2_lsu_bus_buffer.sv" lint_off -rule WIDTHEXPAND -file "*/el2_lsu_stbuf.sv" lint_off -rule WIDTHEXPAND -file "*/el2_lsu_dccm_ctl.sv" lint_off -rule WIDTHEXPAND -file "*/el2_lsu_dccm_mem.sv" lint_off -rule WIDTHEXPAND -file "*/el2_exu_mul_ctl.sv" lint_off -rule WIDTHEXPAND -file "*/el2_dec_tlu_ctl.sv" lint_off -rule WIDTHEXPAND -file "*/el2_dma_ctrl.sv" lint_off -rule WIDTHEXPAND -file "*/el2_dbg.sv" lint_off -rule WIDTHEXPAND -file "*/el2_veer_lockstep.sv" -lines 383 // Unused parameters are probably safe to remove from RTL lint_off -rule UNUSEDPARAM -file "*/axi4_to_ahb.sv" lint_off -rule UNUSEDPARAM -file "*/el2_ifu.sv" lint_off -rule UNUSEDPARAM -file "*/el2_pic_ctrl.sv" lint_off -rule UNUSEDPARAM -file "*/el2_dma_ctrl.sv" lint_off -rule UNUSEDPARAM -file "*/el2_ifu_bp_ctl.sv" lint_off -rule UNUSEDPARAM -file "*/el2_ifu_mem_ctl.sv" lint_off -rule UNUSEDPARAM -file "*/el2_dec_tlu_ctl.sv" lint_off -rule UNUSEDPARAM -file "*/el2_lsu_dccm_ctl.sv" lint_off -rule UNUSEDPARAM -file "*/el2_lsu_dccm_mem.sv" // Gated clock, expected latch lint_off -rule LATCH -file "*/beh_lib.sv" -lines 781 lint_off -rule BLKSEQ -file "*/beh_lib.sv" -lines 783 // The Verilator reports that `core_rst_l` is being used in sync and async nets, // pointing to `rvdff` module as a source of the problem. Since the `rvdff` looks // unrelated to `core_rst_l`, it requires a closer investigation. lint_off -rule SYNCASYNCNET -file "*/el2_veer.sv" -lines 41 // Unused clocks from shadow core lint_off -rule PINCONNECTEMPTY -file "*/el2_veer_lockstep.sv" -lines 1057-1058 // Logic that might be not optimal for event based model used by Verilator lint_off -rule UNOPTFLAT -file "*/axi4_to_ahb.sv" lint_off -rule UNOPTFLAT -file "*/el2_ifu_ifc_ctl.sv" lint_off -rule UNOPTFLAT -file "*/el2_dec_decode_ctl.sv" lint_off -rule UNOPTFLAT -file "*/el2_exu_mul_ctl.sv" lint_off -rule UNOPTFLAT -file "*/el2_exu_div_ctl.sv" lint_off -rule UNOPTFLAT -file "*/el2_lsu.sv" lint_off -rule UNOPTFLAT -file "*/el2_lsu_lsc_ctl.sv" lint_off -rule UNOPTFLAT -file "*/el2_pic_ctrl.sv" // Warnings related to the generated `el2_param.vh` lint_off -rule UNUSEDPARAM -file "*/el2_ifu_compress_ctl.sv" lint_off -rule UNUSEDPARAM -file "*/el2_dec_gpr_ctl.sv" lint_off -rule UNUSEDPARAM -file "*/el2_dec_trigger.sv" lint_off -rule UNUSEDPARAM -file "*/el2_lsu_trigger.sv" lint_off -rule UNUSEDPARAM -file "*/el2_lsu_clkdomain.sv" lint_off -rule WIDTHTRUNC -file "*/el2_ifu_compress_ctl.sv" ================================================ FILE: verification/block/dccm/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_lsu_dccm_mem_wrapper VERILOG_SOURCES = \ $(SRCDIR)/lib/el2_mem_if.sv \ $(TEST_DIR)/el2_lsu_dccm_mem_wrapper.sv \ $(SRCDIR)/lsu/el2_lsu_dccm_mem.sv \ $(SRCDIR)/lib/mem_lib.sv # Undefine the VERILATOR macro to make the code use actual RAM cells instead # of simulation models EXTRA_ARGS += -UVERILATOR include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/dccm/config.vlt ================================================ `verilator_config lint_off -rule PINCONNECTEMPTY -file "*/el2_lsu_dccm_mem_wrapper.sv" lint_off -rule WIDTHTRUNC -file "*/el2_lsu_dccm_mem_wrapper.sv" lint_off -rule IMPORTSTAR -file "*/el2_mem_if.sv" ================================================ FILE: verification/block/dccm/el2_lsu_dccm_mem_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_lsu_dccm_mem_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic active_clk, input logic rst_l, input logic clk_override, input logic dccm_wren, input logic dccm_rden, input logic [pt.DCCM_BITS-1:0] dccm_wr_addr_lo, input logic [pt.DCCM_BITS-1:0] dccm_wr_addr_hi, input logic [pt.DCCM_BITS-1:0] dccm_rd_addr_lo, input logic [pt.DCCM_BITS-1:0] dccm_rd_addr_hi, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo, input logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi, // el2_dccm_ext_in_pkt_t input logic dccm_ext_in_pkt_TEST1, input logic dccm_ext_in_pkt_RME, input logic [3:0] dccm_ext_in_pkt_RM, input logic dccm_ext_in_pkt_LS, input logic dccm_ext_in_pkt_DS, input logic dccm_ext_in_pkt_SD, input logic dccm_ext_in_pkt_TEST_RNM, input logic dccm_ext_in_pkt_BC1, input logic dccm_ext_in_pkt_BC2, output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo, output logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi, input logic scan_mode ); localparam DCCM_ECC_WIDTH = pt.DCCM_FDATA_WIDTH - pt.DCCM_DATA_WIDTH; logic [pt.DCCM_NUM_BANKS-1:0] dccm_clken; logic [pt.DCCM_NUM_BANKS-1:0] dccm_wren_bank; logic [pt.DCCM_NUM_BANKS-1:0][pt.DCCM_BITS-1:(pt.DCCM_BANK_BITS+2)] dccm_addr_bank; logic [pt.DCCM_NUM_BANKS-1:0][ pt.DCCM_DATA_WIDTH-1:0] dccm_wr_data_bank; logic [pt.DCCM_NUM_BANKS-1:0][ DCCM_ECC_WIDTH-1:0] dccm_wr_ecc_bank; logic [pt.DCCM_NUM_BANKS-1:0][ pt.DCCM_DATA_WIDTH-1:0] dccm_bank_dout; logic [pt.DCCM_NUM_BANKS-1:0][ DCCM_ECC_WIDTH-1:0] dccm_bank_ecc; logic [pt.DCCM_NUM_BANKS-1:0][ pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_fdata_bank; logic [pt.DCCM_NUM_BANKS-1:0][ pt.DCCM_FDATA_WIDTH-1:0] dccm_bank_fdout; el2_mem_if mem_export (); assign dccm_clken = mem_export.dccm_clken; assign dccm_wren_bank = mem_export.dccm_wren_bank; assign dccm_addr_bank = mem_export.dccm_addr_bank; assign dccm_wr_data_bank = mem_export.dccm_wr_data_bank; assign dccm_wr_ecc_bank = mem_export.dccm_wr_ecc_bank; // Pack dccm_ext_in_pkt el2_dccm_ext_in_pkt_t [pt.DCCM_NUM_BANKS-1:0] dccm_ext_in_pkt; for (genvar i = 0; i < pt.DCCM_NUM_BANKS; i++) begin : gen_dccm_ext_pkt assign dccm_ext_in_pkt[i].TEST1 = dccm_ext_in_pkt_TEST1; assign dccm_ext_in_pkt[i].RME = dccm_ext_in_pkt_RME; assign dccm_ext_in_pkt[i].RM = dccm_ext_in_pkt_RM; assign dccm_ext_in_pkt[i].LS = dccm_ext_in_pkt_LS; assign dccm_ext_in_pkt[i].DS = dccm_ext_in_pkt_DS; assign dccm_ext_in_pkt[i].SD = dccm_ext_in_pkt_SD; assign dccm_ext_in_pkt[i].TEST_RNM = dccm_ext_in_pkt_TEST_RNM; assign dccm_ext_in_pkt[i].BC1 = dccm_ext_in_pkt_BC1; assign dccm_ext_in_pkt[i].BC2 = dccm_ext_in_pkt_BC2; end : gen_dccm_ext_pkt localparam DCCM_INDEX_DEPTH = ((pt.DCCM_SIZE)*1024)/((pt.DCCM_BYTE_WIDTH)*(pt.DCCM_NUM_BANKS)); // Depth of memory bank // 8 Banks, 16KB each (2048 x 72) for (genvar i = 0; i < pt.DCCM_NUM_BANKS; i++) begin : gen_dccm_mem assign dccm_wr_fdata_bank[i] = { mem_export.dccm_wr_ecc_bank[i], mem_export.dccm_wr_data_bank[i] }; assign mem_export.dccm_bank_dout[i] = dccm_bank_fdout[i][pt.DCCM_DATA_WIDTH-1:0]; assign mem_export.dccm_bank_ecc[i] = dccm_bank_fdout[i][pt.DCCM_FDATA_WIDTH-1:pt.DCCM_DATA_WIDTH]; el2_ram #(DCCM_INDEX_DEPTH, 39) ram ( // Primary ports .ME(dccm_clken[i]), .CLK(clk), .WE(dccm_wren_bank[i]), .ADR(dccm_addr_bank[i]), .D(dccm_wr_fdata_bank[i][pt.DCCM_FDATA_WIDTH-1:0]), .Q(dccm_bank_fdout[i][pt.DCCM_FDATA_WIDTH-1:0]), .ROP(), // These are used by SoC .TEST1(dccm_ext_in_pkt[i].TEST1), .RME(dccm_ext_in_pkt[i].RME), .RM(dccm_ext_in_pkt[i].RM), .LS(dccm_ext_in_pkt[i].LS), .DS(dccm_ext_in_pkt[i].DS), .SD(dccm_ext_in_pkt[i].SD), .TEST_RNM(dccm_ext_in_pkt[i].TEST_RNM), .BC1(dccm_ext_in_pkt[i].BC1), .BC2(dccm_ext_in_pkt[i].BC2), .* ); end : gen_dccm_mem el2_lsu_dccm_mem mem ( .dccm_mem_export(mem_export.veer_dccm), .* ); endmodule ================================================ FILE: verification/block/dccm/test_readwrite.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseTest, MemReadItem, MemWriteItem # ============================================================================= class ReadWriteSequence(uvm_sequence): """ A sequencer that issues a random sequence of writes followed by a randomized sequence of reads containing the same addresses previously written to. """ def __init__(self, name): super().__init__(name) async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") burst = ConfigDB().get(None, "", "TEST_BURST_LEN") awidth = ConfigDB().get(None, "", "DCCM_BITS") dwidth = ConfigDB().get(None, "", "DCCM_FDATA_WIDTH") for i in range(count): # Randomize unique addresses (aligned) addrs = set([random.randrange(0, 1 << awidth) & 0xFFFFFFFC for i in range(burst)]) # Issue writes, randomize data for addr in addrs: data = random.randrange(0, 1 << dwidth) item = MemWriteItem(addr, data) await self.start_item(item) await self.finish_item(item) # Issue random reads for written addresses random.shuffle(list(set(addrs))) for addr in addrs: item = MemReadItem(addr, data) await self.start_item(item) await self.finish_item(item) @pyuvm.test() class TestReadWrite(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = ReadWriteSequence("stimulus") async def run(self): await self.seq.start(self.env.mem_seqr) ================================================ FILE: verification/block/dccm/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import os import pyuvm from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge from pyuvm import * # ============================================================================== class MemWriteItem(uvm_sequence_item): """ Memory write item """ def __init__(self, addr, data): super().__init__("MemWriteItem") self.addr = addr self.data = data class MemReadItem(uvm_sequence_item): """ Memory read item """ def __init__(self, addr, data=None): super().__init__("MemReadItem") self.addr = addr self.data = data # ============================================================================== class MemDriver(uvm_driver): """ Memory interface driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() # Write if isinstance(it, MemWriteItem): # Wait for rising edge, do the write await RisingEdge(self.dut.clk) self.dut.dccm_wren.value = 1 self.dut.dccm_wr_addr_lo.value = it.addr self.dut.dccm_wr_data_lo.value = it.data self.dut.dccm_wr_addr_hi.value = it.addr self.dut.dccm_wr_data_hi.value = it.data # Wait for rising edge, deassert write await RisingEdge(self.dut.clk) self.dut.dccm_wren.value = 0 # Read elif isinstance(it, MemReadItem): # Wait for rising edge, do the read await RisingEdge(self.dut.clk) self.dut.dccm_rden.value = 1 self.dut.dccm_rd_addr_lo.value = it.addr self.dut.dccm_rd_addr_hi.value = it.addr # Wait for rising edge, deassert read await RisingEdge(self.dut.clk) self.dut.dccm_rden.value = 0 else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class MemMonitor(uvm_component): """ Memory interface monitor """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Act on rising edges await RisingEdge(self.dut.clk) # Since the driver drives both lo and hi with the same values # here we sample only lo # Write if self.dut.dccm_wren.value: addr = int(self.dut.dccm_wr_addr_lo) data = int(self.dut.dccm_wr_data_lo) self.ap.write(MemWriteItem(addr, data)) # Read if self.dut.dccm_rden.value: addr = int(self.dut.dccm_rd_addr_lo) # Wait additional clock cycle await RisingEdge(self.dut.clk) data = int(self.dut.dccm_rd_data_lo) self.ap.write(MemReadItem(addr, data)) # ============================================================================== class Scoreboard(uvm_component): """ A scoreboard that tracks memory writes and compares them agains data read from the memory. It also checks if both reads and writes took place """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): did_write = False did_read = False mem_content = dict() # Process items while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Initially pass if self.passed is None: self.passed = True # Memory write if isinstance(item, MemWriteItem): mem_content[item.addr] = item.data did_write = True self.logger.debug("[0x{:08X}] <= 0x{:08X}".format(item.addr, item.data)) # Memory read elif isinstance(item, MemReadItem): data = mem_content.get(item.addr, None) did_read = True self.logger.debug( "[0x{:08X}] == 0x{:08X} vs. 0x{:08X} {}".format( item.addr, item.data, data, item.data == data ) ) if data != item.data: self.logger.error( "Data mismatch, mem[0x{:08X}] is 0x{:08X}, should be 0x{:08X}".format( item.addr, item.data, data ) ) self.passed = False # There were no writes if not did_write: self.logger.error("There were no writes") self.passed = False # There were no reads if not did_read: self.logger.error("There were no reads") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 50) ConfigDB().set(None, "*", "TEST_BURST_LEN", 10) ConfigDB().set(None, "*", "DCCM_BITS", 0x10) ConfigDB().set(None, "*", "DCCM_FDATA_WIDTH", 0x20) # Sequencers self.mem_seqr = uvm_sequencer("mem_seqr", self) # Driver self.mem_drv = MemDriver("mem_drv", self, dut=cocotb.top) # Monitor self.mem_mon = MemMonitor("mem_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): self.mem_drv.seq_item_port.connect(self.mem_seqr.seq_item_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") self.start_clock("active_clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/dcls/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_veer_lockstep_wrapper CM_FILE = cm.cfg EXTRA_VEER_CONFIG = -set lockstep_enable=1 -set lockstep_regfile_enable=1 VERILOG_INCLUDE_DIRS += \ ${RV_ROOT}/testbench \ ${RV_ROOT}/design/include VERILOG_SOURCES = \ ${SRCDIR}/lib/el2_mem_if.sv \ ${SRCDIR}/lib/el2_regfile_if.sv \ ${SRCDIR}/el2_veer_wrapper.sv \ ${SRCDIR}/el2_mem.sv \ ${SRCDIR}/el2_pic_ctrl.sv \ ${SRCDIR}/el2_veer.sv \ ${SRCDIR}/el2_dma_ctrl.sv \ ${SRCDIR}/el2_pmp.sv \ ${SRCDIR}/ifu/el2_ifu_aln_ctl.sv \ ${SRCDIR}/ifu/el2_ifu_compress_ctl.sv \ ${SRCDIR}/ifu/el2_ifu_ifc_ctl.sv \ ${SRCDIR}/ifu/el2_ifu_bp_ctl.sv \ ${SRCDIR}/ifu/el2_ifu_ic_mem.sv \ ${SRCDIR}/ifu/el2_ifu_mem_ctl.sv \ ${SRCDIR}/ifu/el2_ifu_iccm_mem.sv \ ${SRCDIR}/ifu/el2_ifu.sv \ ${SRCDIR}/dec/el2_dec_decode_ctl.sv \ ${SRCDIR}/dec/el2_dec_gpr_ctl.sv \ ${SRCDIR}/dec/el2_dec_ib_ctl.sv \ ${SRCDIR}/dec/el2_dec_pmp_ctl.sv \ ${SRCDIR}/dec/el2_dec_tlu_ctl.sv \ ${SRCDIR}/dec/el2_dec_trigger.sv \ ${SRCDIR}/dec/el2_dec.sv \ ${SRCDIR}/exu/el2_exu_alu_ctl.sv \ ${SRCDIR}/exu/el2_exu_mul_ctl.sv \ ${SRCDIR}/exu/el2_exu_div_ctl.sv \ ${SRCDIR}/exu/el2_exu.sv \ ${SRCDIR}/lsu/el2_lsu.sv \ ${SRCDIR}/lsu/el2_lsu_clkdomain.sv \ ${SRCDIR}/lsu/el2_lsu_addrcheck.sv \ ${SRCDIR}/lsu/el2_lsu_lsc_ctl.sv \ ${SRCDIR}/lsu/el2_lsu_stbuf.sv \ ${SRCDIR}/lsu/el2_lsu_bus_buffer.sv \ ${SRCDIR}/lsu/el2_lsu_bus_intf.sv \ ${SRCDIR}/lsu/el2_lsu_ecc.sv \ ${SRCDIR}/lsu/el2_lsu_dccm_mem.sv \ ${SRCDIR}/lsu/el2_lsu_dccm_ctl.sv \ ${SRCDIR}/lsu/el2_lsu_trigger.sv \ ${SRCDIR}/dbg/el2_dbg.sv \ ${SRCDIR}/dmi/dmi_mux.v \ ${SRCDIR}/dmi/dmi_wrapper.v \ ${SRCDIR}/dmi/dmi_jtag_to_core_sync.v \ ${SRCDIR}/dmi/rvjtag_tap.v \ ${SRCDIR}/lib/el2_lib.sv \ $(SRCDIR)/el2_veer_lockstep.sv \ $(TEST_DIR)/el2_veer_lockstep_wrapper.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/dcls/cm.cfg ================================================ +tree el2_veer_lockstep_wrapper -module el2_veer_lockstep_wrapper ////////////////////////////////// MAIN CORE ////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //////////////////////////////// rvrangecheck ///////////////////////////////// // 'start_addr' and 'region' are tied to module parameters -node el2_veer_lockstep_wrapper.veer*rangecheck.start_addr -node el2_veer_lockstep_wrapper.veer*rangecheck.region /////////////////////////////////// el2_veer ////////////////////////////////// -node el2_veer_lockstep_wrapper.veer.trace_rv_i_address_ip[0] -node el2_veer_lockstep_wrapper.veer.trace_rv_trace_pkt.trace_rv_i_address_ip[0] -node el2_veer_lockstep_wrapper.veer.*hprot[3:1] // Tied to 3'001 /////////////////////////////////// el2_dbg /////////////////////////////////// // Tied to '0 -node el2_veer_lockstep_wrapper.veer.dbg.abstractcs_reg[31:13] -node el2_veer_lockstep_wrapper.veer.dbg.abstractcs_reg[11] -node el2_veer_lockstep_wrapper.veer.dbg.abstractcs_reg[7:4] -node el2_veer_lockstep_wrapper.veer.dbg.dmcontrol_reg[29] -node el2_veer_lockstep_wrapper.veer.dbg.dmcontrol_reg[27:2] -node el2_veer_lockstep_wrapper.veer.dbg.dmstatus_reg[31:20] -node el2_veer_lockstep_wrapper.veer.dbg.dmstatus_reg[15:14] -node el2_veer_lockstep_wrapper.veer.dbg.dmstatus_reg[6:4] -node el2_veer_lockstep_wrapper.veer.dbg.haltsum0_reg[31:1] -node el2_veer_lockstep_wrapper.veer.dbg.sbcs_reg[31:30] -node el2_veer_lockstep_wrapper.veer.dbg.sbcs_reg[28:23] -node el2_veer_lockstep_wrapper.veer.dbg.dmstatus_reg[7] // Tied to '1 -node el2_veer_lockstep_wrapper.veer.dbg.dmstatus_reg[3:0] // Tied to 4'h2 -node el2_veer_lockstep_wrapper.veer.dbg.abstractcs_reg[3:0] // Tied to 4'h2 -node el2_veer_lockstep_wrapper.veer.dbg.sbcs_reg[29] // Tied to '1 -node el2_veer_lockstep_wrapper.veer.dbg.sbcs_reg[11:5] // Tied to 7'h20 -node el2_veer_lockstep_wrapper.veer.dbg.sbcs_reg[4:0] // Tied to 5'b01111 /////////////////////////////////// el2_exu /////////////////////////////////// -node el2_veer_lockstep_wrapper.veer.exu.i_mul.crc32_poly_rev // Tied to 32'hEDB88320 -node el2_veer_lockstep_wrapper.veer.exu.i_mul.crc32c_poly_rev // Tied to 32'h82F63B78 ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node el2_veer_lockstep_wrapper.veer.dec.tlu.dcsr[14] -node el2_veer_lockstep_wrapper.veer.dec.tlu.dcsr[9] -node el2_veer_lockstep_wrapper.veer.dec.tlu.dcsr[5:4] -node el2_veer_lockstep_wrapper.veer.dec.tlu.dcsr_ns[14] -node el2_veer_lockstep_wrapper.veer.dec.tlu.dcsr_ns[9] -node el2_veer_lockstep_wrapper.veer.dec.tlu.dcsr_ns[5:4] -node el2_veer_lockstep_wrapper.veer.dec.tlu.ifu_mscause[2] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mcgc[6] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mcgc_int[6] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mcgc_ns[6] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mcountinhibit[1] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mepc_rf[0] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mie_rf[31] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mie_rf[27:12] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mie_rf[10:8] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mie_rf[6:4] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mie_rf[2:0] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mip_rf[27:12] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mip_rf[10:8] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mip_rf[6:4] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mip_rf[2:0] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mstatus_rf[31:17] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mstatus_rf[15:12] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mstatus_rf[10:8] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mstatus_rf[6:4] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mstatus_rf[2:0] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mtdata1_tsel_out[26] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mtdata1_tsel_out[18:13] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mtdata1_tsel_out[10:8] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mtdata1_tsel_out[5:3] -node el2_veer_lockstep_wrapper.veer.dec.tlu.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node el2_veer_lockstep_wrapper.veer.dec.tlu.pmp.*pmpcfg_ff.din[6:5] -node el2_veer_lockstep_wrapper.veer.dec.tlu.pmp.*pmpcfg_ff.dout[6:5] -node el2_veer_lockstep_wrapper.veer.dec.tlu.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node el2_veer_lockstep_wrapper.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[30:29] -node el2_veer_lockstep_wrapper.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[22:21] -node el2_veer_lockstep_wrapper.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[14:13] -node el2_veer_lockstep_wrapper.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[6:5] ////////////////////////////////// LOCKSTEP /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //////////////////////////////// rvrangecheck ///////////////////////////////// // 'start_addr' and 'region' are tied to module parameters -node el2_veer_lockstep_wrapper.lockstep.xshadow_core*rangecheck.start_addr -node el2_veer_lockstep_wrapper.lockstep.xshadow_core*rangecheck.region ////////////////////////////// el2_veer_lockstep ////////////////////////////// -node el2_veer_lockstep_wrapper.lockstep.trace_rv_i_address_ip[0] -node el2_veer_lockstep_wrapper.lockstep.*trace_rv_i_address_ip[0] /////////////////////////////////// el2_veer ////////////////////////////////// -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.trace_rv_i_address_ip[0] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.trace_rv_trace_pkt.trace_rv_i_address_ip[0] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.*hprot[3:1] // Tied to 3'001 /////////////////////////////////// el2_dbg /////////////////////////////////// // Tied to '0 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.abstractcs_reg[31:13] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.abstractcs_reg[11] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.abstractcs_reg[7:4] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.dmcontrol_reg[29] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.dmcontrol_reg[27:2] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.dmstatus_reg[31:20] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.dmstatus_reg[15:14] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.dmstatus_reg[6:4] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.haltsum0_reg[31:1] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.sbcs_reg[31:30] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.sbcs_reg[28:23] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.dmstatus_reg[7] // Tied to '1 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.dmstatus_reg[3:0] // Tied to 4'h2 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.abstractcs_reg[3:0] // Tied to 4'h2 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.sbcs_reg[29] // Tied to '1 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.sbcs_reg[11:5] // Tied to 7'h20 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dbg.sbcs_reg[4:0] // Tied to 5'b01111 /////////////////////////////////// el2_exu /////////////////////////////////// -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.exu.i_mul.crc32_poly_rev // Tied to 32'hEDB88320 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.exu.i_mul.crc32c_poly_rev // Tied to 32'h82F63B78 ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.dcsr[14] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.dcsr[9] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.dcsr[5:4] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.dcsr_ns[14] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.dcsr_ns[9] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.dcsr_ns[5:4] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.ifu_mscause[2] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mcgc[6] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mcgc_int[6] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mcgc_ns[6] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mcountinhibit[1] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mepc_rf[0] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mie_rf[31] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mie_rf[27:12] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mie_rf[10:8] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mie_rf[6:4] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mie_rf[2:0] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mip_rf[27:12] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mip_rf[10:8] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mip_rf[6:4] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mip_rf[2:0] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mstatus_rf[31:17] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mstatus_rf[15:12] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mstatus_rf[10:8] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mstatus_rf[6:4] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mstatus_rf[2:0] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[26] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[18:13] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[10:8] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[5:3] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.pmp.*pmpcfg_ff.din[6:5] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.pmp.*pmpcfg_ff.dout[6:5] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[30:29] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[22:21] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[14:13] -node el2_veer_lockstep_wrapper.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[6:5] ================================================ FILE: verification/block/dcls/el2_veer_lockstep_wrapper.sv ================================================ // Copyright (c) 2024 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_veer_lockstep_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic dbg_rst_l, output logic shadow_reset, output logic shadow_dbg_reset, // Shadow Core control input logic disable_corruption_detection_i, input logic lockstep_err_injection_en_i, // Equivalency Checker output logic corruption_detected_o ); logic core_rst_l; // This is "rst_l | dbg_rst_l" logic [31:1] rst_vec; logic [31:1] nmi_vec; logic nmi_int; logic timer_int; logic soft_int; logic [pt.PIC_TOTAL_INT:1] extintsrc_req; logic active_l2clk; logic free_l2clk; logic [31:0] trace_rv_i_insn_ip; logic [31:0] trace_rv_i_address_ip; logic trace_rv_i_valid_ip; logic trace_rv_i_exception_ip; logic [ 4:0] trace_rv_i_ecause_ip; logic trace_rv_i_interrupt_ip; logic [31:0] trace_rv_i_tval_ip; logic dccm_clk_override; logic icm_clk_override; logic dec_tlu_core_ecc_disable; // external halt/run interface logic i_cpu_halt_req; // Asynchronous Halt request to CPU logic i_cpu_run_req; // Asynchronous Restart request to CPU logic o_cpu_halt_ack; // Core Acknowledge to Halt request logic o_cpu_halt_status; // 1'b1 indicates processor is halted logic o_cpu_run_ack; // Core Acknowledge to run request logic o_debug_mode_status; // Core to the PMU that core is in debug mode. When core is in debug mode; the PMU should refrain from sendng a halt or run request logic [31:4] core_id; // CORE ID // external MPC halt/run interface logic mpc_debug_halt_req; // Async halt request logic mpc_debug_run_req; // Async run request logic mpc_reset_run_req; // Run/halt after reset logic mpc_debug_halt_ack; // Halt ack logic mpc_debug_run_ack; // Run ack logic debug_brkpt_status; // debug breakpoint logic dec_tlu_perfcnt0; // toggles when slot0 perf counter 0 has an event inc logic dec_tlu_perfcnt1; logic dec_tlu_perfcnt2; logic dec_tlu_perfcnt3; // DCCM ports logic dccm_wren; logic dccm_rden; logic [ pt.DCCM_BITS-1:0] dccm_wr_addr_lo; logic [ pt.DCCM_BITS-1:0] dccm_wr_addr_hi; logic [ pt.DCCM_BITS-1:0] dccm_rd_addr_lo; logic [ pt.DCCM_BITS-1:0] dccm_rd_addr_hi; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_lo; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_wr_data_hi; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_lo; logic [pt.DCCM_FDATA_WIDTH-1:0] dccm_rd_data_hi; // ICCM ports logic [pt.ICCM_BITS-1:1] iccm_rw_addr; logic iccm_wren; logic iccm_rden; logic [ 2:0] iccm_wr_size; logic [ 77:0] iccm_wr_data; logic iccm_buf_correct_ecc; logic iccm_correction_state; logic [63:0] iccm_rd_data; logic [77:0] iccm_rd_data_ecc; // ICache ; ITAG ports logic [ 31:1] ic_rw_addr; logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid; logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en; logic ic_rd_en; logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data; // Data to fill to the Icache. With ECC logic [ 63:0] ic_rd_data ; // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC logic [ 70:0] ic_debug_rd_data ; // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC logic [ 25:0] ictag_debug_rd_data;// Debug icache tag. logic [ 70:0] ic_debug_wr_data; // Debug wr cache. logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr; logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr; logic [ 63:0] ic_premux_data; // Premux data to be muxed with each way of the Icache. logic ic_sel_premux_data; // Select premux data logic [ pt.ICACHE_INDEX_HI:3] ic_debug_addr; // Read/Write addresss to the Icache. logic ic_debug_rd_en; // Icache debug rd logic ic_debug_wr_en; // Icache debug wr logic ic_debug_tag_array; // Debug tag array logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way; // Debug way. Rd or Wr. logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit; logic ic_tag_perr; // Icache Tag parity error //-------------------------- LSU AXI signals-------------------------- // AXI Write Channels logic lsu_axi_awvalid; logic lsu_axi_awready; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_awid; logic [ 31:0] lsu_axi_awaddr; logic [ 3:0] lsu_axi_awregion; logic [ 7:0] lsu_axi_awlen; logic [ 2:0] lsu_axi_awsize; logic [ 1:0] lsu_axi_awburst; logic lsu_axi_awlock; logic [ 3:0] lsu_axi_awcache; logic [ 2:0] lsu_axi_awprot; logic [ 3:0] lsu_axi_awqos; logic lsu_axi_wvalid; logic lsu_axi_wready; logic [63:0] lsu_axi_wdata; logic [ 7:0] lsu_axi_wstrb; logic lsu_axi_wlast; logic lsu_axi_bvalid; logic lsu_axi_bready; logic [ 1:0] lsu_axi_bresp; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_bid; // AXI Read Channels logic lsu_axi_arvalid; logic lsu_axi_arready; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_arid; logic [ 31:0] lsu_axi_araddr; logic [ 3:0] lsu_axi_arregion; logic [ 7:0] lsu_axi_arlen; logic [ 2:0] lsu_axi_arsize; logic [ 1:0] lsu_axi_arburst; logic lsu_axi_arlock; logic [ 3:0] lsu_axi_arcache; logic [ 2:0] lsu_axi_arprot; logic [ 3:0] lsu_axi_arqos; logic lsu_axi_rvalid; logic lsu_axi_rready; logic [pt.LSU_BUS_TAG-1:0] lsu_axi_rid; logic [ 63:0] lsu_axi_rdata; logic [ 1:0] lsu_axi_rresp; logic lsu_axi_rlast; //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels logic ifu_axi_awvalid; logic ifu_axi_awready; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid; logic [ 31:0] ifu_axi_awaddr; logic [ 3:0] ifu_axi_awregion; logic [ 7:0] ifu_axi_awlen; logic [ 2:0] ifu_axi_awsize; logic [ 1:0] ifu_axi_awburst; logic ifu_axi_awlock; logic [ 3:0] ifu_axi_awcache; logic [ 2:0] ifu_axi_awprot; logic [ 3:0] ifu_axi_awqos; logic ifu_axi_wvalid; logic ifu_axi_wready; logic [63:0] ifu_axi_wdata; logic [ 7:0] ifu_axi_wstrb; logic ifu_axi_wlast; logic ifu_axi_bvalid; logic ifu_axi_bready; logic [ 1:0] ifu_axi_bresp; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_bid; // AXI Read Channels logic ifu_axi_arvalid; logic ifu_axi_arready; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid; logic [ 31:0] ifu_axi_araddr; logic [ 3:0] ifu_axi_arregion; logic [ 7:0] ifu_axi_arlen; logic [ 2:0] ifu_axi_arsize; logic [ 1:0] ifu_axi_arburst; logic ifu_axi_arlock; logic [ 3:0] ifu_axi_arcache; logic [ 2:0] ifu_axi_arprot; logic [ 3:0] ifu_axi_arqos; logic ifu_axi_rvalid; logic ifu_axi_rready; logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid; logic [ 63:0] ifu_axi_rdata; logic [ 1:0] ifu_axi_rresp; logic ifu_axi_rlast; //-------------------------- SB AXI signals-------------------------- // AXI Write Channels logic sb_axi_awvalid; logic sb_axi_awready; logic [pt.SB_BUS_TAG-1:0] sb_axi_awid; logic [ 31:0] sb_axi_awaddr; logic [ 3:0] sb_axi_awregion; logic [ 7:0] sb_axi_awlen; logic [ 2:0] sb_axi_awsize; logic [ 1:0] sb_axi_awburst; logic sb_axi_awlock; logic [ 3:0] sb_axi_awcache; logic [ 2:0] sb_axi_awprot; logic [ 3:0] sb_axi_awqos; logic sb_axi_wvalid; logic sb_axi_wready; logic [63:0] sb_axi_wdata; logic [ 7:0] sb_axi_wstrb; logic sb_axi_wlast; logic sb_axi_bvalid; logic sb_axi_bready; logic [ 1:0] sb_axi_bresp; logic [pt.SB_BUS_TAG-1:0] sb_axi_bid; // AXI Read Channels logic sb_axi_arvalid; logic sb_axi_arready; logic [pt.SB_BUS_TAG-1:0] sb_axi_arid; logic [ 31:0] sb_axi_araddr; logic [ 3:0] sb_axi_arregion; logic [ 7:0] sb_axi_arlen; logic [ 2:0] sb_axi_arsize; logic [ 1:0] sb_axi_arburst; logic sb_axi_arlock; logic [ 3:0] sb_axi_arcache; logic [ 2:0] sb_axi_arprot; logic [ 3:0] sb_axi_arqos; logic sb_axi_rvalid; logic sb_axi_rready; logic [pt.SB_BUS_TAG-1:0] sb_axi_rid; logic [ 63:0] sb_axi_rdata; logic [ 1:0] sb_axi_rresp; logic sb_axi_rlast; //-------------------------- DMA AXI signals-------------------------- // AXI Write Channels logic dma_axi_awvalid; logic dma_axi_awready; logic [pt.DMA_BUS_TAG-1:0] dma_axi_awid; logic [ 31:0] dma_axi_awaddr; logic [ 2:0] dma_axi_awsize; logic [ 2:0] dma_axi_awprot; logic [ 7:0] dma_axi_awlen; logic [ 1:0] dma_axi_awburst; logic dma_axi_wvalid; logic dma_axi_wready; logic [63:0] dma_axi_wdata; logic [ 7:0] dma_axi_wstrb; logic dma_axi_wlast; logic dma_axi_bvalid; logic dma_axi_bready; logic [ 1:0] dma_axi_bresp; logic [pt.DMA_BUS_TAG-1:0] dma_axi_bid; // AXI Read Channels logic dma_axi_arvalid; logic dma_axi_arready; logic [pt.DMA_BUS_TAG-1:0] dma_axi_arid; logic [ 31:0] dma_axi_araddr; logic [ 2:0] dma_axi_arsize; logic [ 2:0] dma_axi_arprot; logic [ 7:0] dma_axi_arlen; logic [ 1:0] dma_axi_arburst; logic dma_axi_rvalid; logic dma_axi_rready; logic [pt.DMA_BUS_TAG-1:0] dma_axi_rid; logic [ 63:0] dma_axi_rdata; logic [ 1:0] dma_axi_rresp; logic dma_axi_rlast; //// AHB LITE BUS logic [31:0] haddr; logic [ 2:0] hburst; logic hmastlock; logic [ 3:0] hprot; logic [ 2:0] hsize; logic [ 1:0] htrans; logic hwrite; logic [63:0] hrdata; logic hready; logic hresp; // LSU AHB Master logic [31:0] lsu_haddr; logic [ 2:0] lsu_hburst; logic lsu_hmastlock; logic [ 3:0] lsu_hprot; logic [ 2:0] lsu_hsize; logic [ 1:0] lsu_htrans; logic lsu_hwrite; logic [63:0] lsu_hwdata; logic [63:0] lsu_hrdata; logic lsu_hready; logic lsu_hresp; //System Bus Debug Master logic [31:0] sb_haddr; logic [ 2:0] sb_hburst; logic sb_hmastlock; logic [ 3:0] sb_hprot; logic [ 2:0] sb_hsize; logic [ 1:0] sb_htrans; logic sb_hwrite; logic [63:0] sb_hwdata; logic [63:0] sb_hrdata; logic sb_hready; logic sb_hresp; // DMA Slave logic dma_hsel; logic [31:0] dma_haddr; logic [ 2:0] dma_hburst; logic dma_hmastlock; logic [ 3:0] dma_hprot; logic [ 2:0] dma_hsize; logic [ 1:0] dma_htrans; logic dma_hwrite; logic [63:0] dma_hwdata; logic dma_hreadyin; logic [63:0] dma_hrdata; logic dma_hreadyout; logic dma_hresp; logic lsu_bus_clk_en; logic ifu_bus_clk_en; logic dbg_bus_clk_en; logic dma_bus_clk_en; logic dmi_reg_en; // read or write logic [ 6:0] dmi_reg_addr; // address of DM register logic dmi_reg_wr_en; // write instruction logic [31:0] dmi_reg_wdata; // write data logic [31:0] dmi_reg_rdata; // ICCM/DCCM ECC status logic iccm_ecc_single_error; logic iccm_ecc_double_error; logic dccm_ecc_single_error; logic dccm_ecc_double_error; logic scan_mode; `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_regfile_if regfile (); `endif // `ifdef RV_LOCKSTEP_REGFILE_ENABLE el2_veer #(.pt(pt)) veer ( `ifdef RV_LOCKSTEP_REGFILE_ENABLE .regfile(regfile.veer_rf_src), `endif // `ifdef RV_LOCKSTEP_REGFILE_ENABLE .* ); el2_veer_lockstep #(.pt(pt)) lockstep ( `ifdef RV_LOCKSTEP_REGFILE_ENABLE .main_core_regfile(regfile.veer_rf_sink), `endif // `ifdef RV_LOCKSTEP_REGFILE_ENABLE .* ); assign shadow_reset = lockstep.rst_shadow; assign shadow_dbg_reset = lockstep.rst_dbg_shadow; endmodule ================================================ FILE: verification/block/dcls/test_lockstep.py ================================================ # Copyright (c) 2024 Antmicro # SPDX-License-Identifier: Apache-2.0 from random import randrange import pyuvm from cocotb.triggers import ClockCycles, ReadOnly, RisingEdge from cocotb.utils import get_sim_time from pyuvm import ConfigDB from testbench import BaseTest # ============================================================================= @pyuvm.test() class TestReset(BaseTest): """ A basic test that resets the DUT and ensures shadow core gets out of reset after the configured delay """ def assert_signals(self, signals): time = get_sim_time(units="ns") self.logger.info(f"Validating signals at {time}") for name, value in signals.items(): try: sig = getattr(self.dut, name) except AttributeError: print(f"DUT does not contain signal named {name}") exit(1) self.logger.info(f"Assert that {name}={value}") assert sig.value == value async def test_reset(self): lockstep_delay = ConfigDB().get(None, "", "LOCKSTEP_DELAY") signals = { "shadow_reset": 0, "shadow_dbg_reset": 0, "corruption_detected_o": 0, } # The shadow core should go into the reset regardless of the delay for _ in range(lockstep_delay): await ReadOnly() self.assert_signals(signals) await RisingEdge(self.clk) # After the delay shadow core should be out of reset without corruption detected signals.update({"shadow_reset": 1, "shadow_dbg_reset": 1}) await ReadOnly() self.assert_signals(signals) await RisingEdge(self.clk) async def run(self): await self.test_reset() @pyuvm.test() class TestErrorInjection(TestReset): """ A test that ensures the Shadow Core reports a corruption after enabling an error injection. """ async def run(self): # Get out of reset await self.test_reset() # Await few cycles (arbitrary number) await ClockCycles(self.clk, 10) # Enable error injection self.dut.lockstep_err_injection_en_i.value = 1 await RisingEdge(self.clk) # Assert that an error is detected signals = { "shadow_reset": 1, "shadow_dbg_reset": 1, "corruption_detected_o": 1, } self.assert_signals(signals) # Disable the Shadow Core self.dut.disable_corruption_detection_i.value = 1 await RisingEdge(self.clk) # Assert that an error is not detected signals.update({"corruption_detected_o": 0}) self.assert_signals(signals) ================================================ FILE: verification/block/dcls/testbench.py ================================================ # Copyright (c) 2024 Antmicro # SPDX-License-Identifier: Apache-2.0 import logging import os import cocotb from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge from pyuvm import ConfigDB, uvm_env, uvm_report_object, uvm_test class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "LOCKSTEP_DELAY", 3) def connect_phase(self): pass # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class self.dut = cocotb.top self.clk = self.dut.clk # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(self.dut, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): self.dut.rst_l.value = 0 self.dut.dbg_rst_l.value = 0 await ClockCycles(self.dut.clk, 2) await FallingEdge(self.dut.clk) self.dut.rst_l.value = 1 self.dut.dbg_rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() await RisingEdge(self.clk) # Run the actual test await self.run() # Wait some cycles await ClockCycles(self.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/dec/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_dec_wrapper DEC_TEST := 1 CM_FILE = cm.cfg EXTRA_ARGS = -I$(SRCDIR)/include/ VERILOG_SOURCES = \ $(TEST_DIR)/el2_dec_wrapper.sv \ $(SRCDIR)/dec/el2_dec.sv \ $(SRCDIR)/dec/el2_dec_decode_ctl.sv \ $(SRCDIR)/dec/el2_dec_gpr_ctl.sv \ $(SRCDIR)/dec/el2_dec_ib_ctl.sv \ $(SRCDIR)/dec/el2_dec_pmp_ctl.sv \ $(SRCDIR)/dec/el2_dec_tlu_ctl.sv \ $(SRCDIR)/dec/el2_dec_trigger.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/dec/cm.cfg ================================================ +tree el2_dec_wrapper.dut ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node el2_dec_wrapper.dut.tlu.dcsr[14] -node el2_dec_wrapper.dut.tlu.dcsr[9] -node el2_dec_wrapper.dut.tlu.dcsr[5:4] -node el2_dec_wrapper.dut.tlu.dcsr_ns[14] -node el2_dec_wrapper.dut.tlu.dcsr_ns[9] -node el2_dec_wrapper.dut.tlu.dcsr_ns[5:4] -node el2_dec_wrapper.dut.tlu.ifu_mscause[2] -node el2_dec_wrapper.dut.tlu.mcgc[6] -node el2_dec_wrapper.dut.tlu.mcgc_int[6] -node el2_dec_wrapper.dut.tlu.mcgc_ns[6] -node el2_dec_wrapper.dut.tlu.mcountinhibit[1] -node el2_dec_wrapper.dut.tlu.mepc_rf[0] -node el2_dec_wrapper.dut.tlu.mie_rf[31] -node el2_dec_wrapper.dut.tlu.mie_rf[27:12] -node el2_dec_wrapper.dut.tlu.mie_rf[10:8] -node el2_dec_wrapper.dut.tlu.mie_rf[6:4] -node el2_dec_wrapper.dut.tlu.mie_rf[2:0] -node el2_dec_wrapper.dut.tlu.mip_rf[27:12] -node el2_dec_wrapper.dut.tlu.mip_rf[10:8] -node el2_dec_wrapper.dut.tlu.mip_rf[6:4] -node el2_dec_wrapper.dut.tlu.mip_rf[2:0] -node el2_dec_wrapper.dut.tlu.mstatus_rf[31:17] -node el2_dec_wrapper.dut.tlu.mstatus_rf[15:12] -node el2_dec_wrapper.dut.tlu.mstatus_rf[10:8] -node el2_dec_wrapper.dut.tlu.mstatus_rf[6:4] -node el2_dec_wrapper.dut.tlu.mstatus_rf[2:0] -node el2_dec_wrapper.dut.tlu.mtdata1_tsel_out[26] -node el2_dec_wrapper.dut.tlu.mtdata1_tsel_out[18:13] -node el2_dec_wrapper.dut.tlu.mtdata1_tsel_out[10:8] -node el2_dec_wrapper.dut.tlu.mtdata1_tsel_out[5:3] -node el2_dec_wrapper.dut.tlu.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node el2_dec_wrapper.dut.tlu.pmp.*pmpcfg_ff.din[6:5] -node el2_dec_wrapper.dut.tlu.pmp.*pmpcfg_ff.dout[6:5] -node el2_dec_wrapper.dut.tlu.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node el2_dec_wrapper.dut.tlu.pmp.pmp_pmpcfg_rddata[30:29] -node el2_dec_wrapper.dut.tlu.pmp.pmp_pmpcfg_rddata[22:21] -node el2_dec_wrapper.dut.tlu.pmp.pmp_pmpcfg_rddata[14:13] -node el2_dec_wrapper.dut.tlu.pmp.pmp_pmpcfg_rddata[6:5] ================================================ FILE: verification/block/dec/el2_dec_wrapper.sv ================================================ module el2_dec_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic free_clk, // Clock always. Through two clock headers. For flops without second clock header built in. input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in. input logic lsu_fastint_stall_any, // needed by lsu for 2nd pass of dma with ecc correction, stall next cycle output logic dec_extint_stall, // Stall on external interrupt output logic dec_i0_decode_d, // Valid instruction at D-stage and not blocked output logic dec_pause_state_cg, // to top for active state clock gating output logic dec_tlu_core_empty, input logic rst_l, // reset, active low // rst_vec is supposed to be connected to a constant in the top level /*pragma coverage off*/ input logic [31:1] rst_vec, // reset vector, from core pins /*pragma coverage on*/ input logic nmi_int, // NMI pin // nmi_vec is supposed to be connected to a constant in the top level /*pragma coverage off*/ input logic [31:1] nmi_vec, // NMI vector, from pins /*pragma coverage on*/ input logic i_cpu_halt_req, // Asynchronous Halt request to CPU input logic i_cpu_run_req, // Asynchronous Restart request to CPU output logic o_cpu_halt_status, // Halt status of core (pmu/fw) output logic o_cpu_halt_ack, // Halt request ack output logic o_cpu_run_ack, // Run request ack output logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request /*pragma coverage off*/ input logic [31:4] core_id, // CORE ID /*pragma coverage on*/ // external MPC halt/run interface input logic mpc_debug_halt_req, // Async halt request input logic mpc_debug_run_req, // Async run request input logic mpc_reset_run_req, // Run/halt after reset output logic mpc_debug_halt_ack, // Halt ack output logic mpc_debug_run_ack, // Run ack output logic debug_brkpt_status, // debug breakpoint input logic exu_pmu_i0_br_misp, // slot 0 branch misp input logic exu_pmu_i0_br_ataken, // slot 0 branch actual taken input logic exu_pmu_i0_pc4, // slot 0 4 byte branch input logic lsu_nonblock_load_valid_m, // valid nonblock load at m input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_tag_m, // -> corresponding tag input logic lsu_nonblock_load_inv_r, // invalidate request for nonblock load r input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_inv_tag_r, // -> corresponding tag input logic lsu_nonblock_load_data_valid, // valid nonblock load data back input logic lsu_nonblock_load_data_error, // nonblock load bus error input logic [pt.LSU_NUM_NBLOAD_WIDTH-1:0] lsu_nonblock_load_data_tag, // -> corresponding tag input logic [31:0] lsu_nonblock_load_data, // nonblock load data input logic lsu_pmu_bus_trxn, // D side bus transaction input logic lsu_pmu_bus_misaligned, // D side bus misaligned input logic lsu_pmu_bus_error, // D side bus error input logic lsu_pmu_bus_busy, // D side bus busy input logic lsu_pmu_misaligned_m, // D side load or store misaligned input logic lsu_pmu_load_external_m, // D side bus load input logic lsu_pmu_store_external_m, // D side bus store input logic dma_pmu_dccm_read, // DMA DCCM read input logic dma_pmu_dccm_write, // DMA DCCM write input logic dma_pmu_any_read, // DMA read input logic dma_pmu_any_write, // DMA write input logic [31:1] lsu_fir_addr, // Fast int address input logic [ 1:0] lsu_fir_error, // Fast int lookup error input logic ifu_pmu_instr_aligned, // aligned instructions input logic ifu_pmu_fetch_stall, // fetch unit stalled input logic ifu_pmu_ic_miss, // icache miss input logic ifu_pmu_ic_hit, // icache hit input logic ifu_pmu_bus_error, // Instruction side bus error input logic ifu_pmu_bus_busy, // Instruction side bus busy input logic ifu_pmu_bus_trxn, // Instruction side bus transaction input logic ifu_ic_error_start, // IC single bit error input logic ifu_iccm_rd_ecc_single_err, // ICCM single bit error input logic [ 3:0] lsu_trigger_match_m, input logic dbg_cmd_valid, // debugger abstract command valid input logic dbg_cmd_write, // command is a write input logic [ 1:0] dbg_cmd_type, // command type input logic [31:0] dbg_cmd_addr, // command address input logic [ 1:0] dbg_cmd_wrdata, // command write data, for fence/fence_i input logic ifu_i0_icaf, // icache access fault input logic [1:0] ifu_i0_icaf_type, // icache access fault type input logic ifu_i0_icaf_second, // i0 has access fault on second 2B of 4B inst input logic ifu_i0_dbecc, // icache/iccm double-bit error input logic lsu_idle_any, // lsu idle for halting input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index input logic [ pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR input logic [ pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag input logic [ $clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index input logic lsu_single_ecc_error_incr, // LSU inc SB error counter input logic lsu_imprecise_error_load_any, // LSU imprecise load bus error input logic lsu_imprecise_error_store_any, // LSU imprecise store bus error input logic [31:0] lsu_imprecise_error_addr_any, // LSU imprecise bus error address input logic [31:0] exu_div_result, // final div result input logic exu_div_wren, // Divide write enable to GPR input logic [31:0] exu_csr_rs1_x, // rs1 for csr instruction input logic [31:0] lsu_result_m, // load result input logic [31:0] lsu_result_corr_r, // load result - corrected load data input logic lsu_load_stall_any, // This is for blocking loads input logic lsu_store_stall_any, // This is for blocking stores input logic dma_dccm_stall_any, // stall any load/store at decode, pmu event input logic dma_iccm_stall_any, // iccm stalled, pmu event input logic iccm_dma_sb_error, // ICCM DMA single bit error input logic exu_flush_final, // slot0 flush input logic [31:1] exu_npc_r, // next PC input logic [31:0] exu_i0_result_x, // alu result x input logic ifu_i0_valid, // fetch valids to instruction buffer input logic [31:0] ifu_i0_instr, // fetch inst's to instruction buffer input logic [31:1] ifu_i0_pc, // pc's for instruction buffer input logic ifu_i0_pc4, // indication of 4B or 2B for corresponding inst input logic [31:1] exu_i0_pc_x, // pc's for e1 from the alu's input logic mexintpend, // External interrupt pending input logic timer_int, // Timer interrupt pending (from pin) input logic soft_int, // Software interrupt pending (from pin) input logic [7:0] pic_claimid, // PIC claimid input logic [3:0] pic_pl, // PIC priv level input logic mhwakeup, // High priority wakeup output logic [3:0] dec_tlu_meicurpl, // to PIC, Current priv level output logic [3:0] dec_tlu_meipt, // to PIC input logic [70:0] ifu_ic_debug_rd_data, // diagnostic icache read data input logic ifu_ic_debug_rd_data_valid, // diagnostic icache read data valid output el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt, // packet of DICAWICS, DICAD0/1, DICAGO info for icache diagnostics // Debug start input logic dbg_halt_req, // DM requests a halt input logic dbg_resume_req, // DM requests a resume input logic ifu_miss_state_idle, // I-side miss buffer empty output logic dec_tlu_dbg_halted, // Core is halted and ready for debug command output logic dec_tlu_debug_mode, // Core is in debug mode output logic dec_tlu_resume_ack, // Resume acknowledge output logic dec_tlu_flush_noredir_r, // Tell fetch to idle on this flush output logic dec_tlu_mpc_halted_only, // Core is halted only due to MPC output logic dec_tlu_flush_leak_one_r, // single step output logic dec_tlu_flush_err_r, // iside perr/ecc rfpc output logic [31:2] dec_tlu_meihap, // Fast ext int base output logic dec_debug_wdata_rs1_d, // insert debug write data into rs1 at decode output logic [31:0] dec_dbg_rddata, // debug command read data output logic dec_dbg_cmd_done, // abstract command is done output logic dec_dbg_cmd_fail, // abstract command failed (illegal reg address) // el2_trigger_pkt_t broken down to allow driving from cocotb by both SIMs // info needed by debug trigger blocks output logic [3:0] trigger_pkt_any_select, output logic [3:0] trigger_pkt_any_match, output logic [3:0] trigger_pkt_any_store, output logic [3:0] trigger_pkt_any_load, output logic [3:0] trigger_pkt_any_execute, output logic [3:0] trigger_pkt_any_m, output logic [3:0][31:0] trigger_pkt_any_tdata2, output logic dec_tlu_force_halt, // halt has been forced // Debug end // branch info from pipe0 for errors or counter updates input logic [1:0] exu_i0_br_hist_r, // history input logic exu_i0_br_error_r, // error input logic exu_i0_br_start_error_r, // start error input logic exu_i0_br_valid_r, // valid input logic exu_i0_br_mp_r, // mispredict input logic exu_i0_br_middle_r, // middle of bank // branch info from pipe1 for errors or counter updates input logic exu_i0_br_way_r, // way hit or repl output logic dec_i0_rs1_en_d, // Qualify GPR RS1 data output logic dec_i0_rs2_en_d, // Qualify GPR RS2 data output logic [31:0] gpr_i0_rs1_d, // gpr rs1 data output logic [31:0] gpr_i0_rs2_d, // gpr rs2 data output logic [31:0] dec_i0_immed_d, // immediate data output logic [12:1] dec_i0_br_immed_d, // br immediate data output el2_alu_pkt_t i0_ap, // alu packet output logic dec_i0_alu_decode_d, // schedule on D-stage alu output logic dec_i0_branch_d, // Branch in D-stage output logic dec_i0_select_pc_d, // select pc onto rs1 for jal's output logic [31:1] dec_i0_pc_d, // pc's at decode output logic [ 3:0] dec_i0_rs1_bypass_en_d, // rs1 bypass enable output logic [ 3:0] dec_i0_rs2_bypass_en_d, // rs2 bypass enable output logic [31:0] dec_i0_result_r, // Result R-stage output el2_lsu_pkt_t lsu_p, // lsu packet output logic dec_qual_lsu_d, // LSU instruction at D. Use to quiet LSU operands output el2_mul_pkt_t mul_p, // mul packet output el2_div_pkt_t div_p, // div packet output logic dec_div_cancel, // cancel divide operation output logic [11:0] dec_lsu_offset_d, // 12b offset for load/store addresses output logic dec_csr_ren_d, // CSR read enable output logic [31:0] dec_csr_rddata_d, // CSR read data output logic dec_tlu_flush_lower_r, // tlu flush due to late mp, exception, rfpc, or int output logic dec_tlu_flush_lower_wb, output logic [31:1] dec_tlu_flush_path_r, // tlu flush target output logic dec_tlu_i0_kill_writeb_r, // I0 is flushed, don't writeback any results to arch state output logic dec_tlu_fence_i_r, // flush is a fence_i rfnpc, flush icache output logic [31:1] pred_correct_npc_x, // npc if prediction is correct at e2 stage output el2_br_tlu_pkt_t dec_tlu_br0_r_pkt, // slot 0 branch predictor update packet output logic dec_tlu_perfcnt0, // toggles when slot0 perf counter 0 has an event inc output logic dec_tlu_perfcnt1, // toggles when slot0 perf counter 1 has an event inc output logic dec_tlu_perfcnt2, // toggles when slot0 perf counter 2 has an event inc output logic dec_tlu_perfcnt3, // toggles when slot0 perf counter 3 has an event inc output el2_predict_pkt_t dec_i0_predict_p_d, // prediction packet to alus output logic [pt.BHT_GHR_SIZE-1:0] i0_predict_fghr_d, // DEC predict fghr output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] i0_predict_index_d, // DEC predict index output logic [pt.BTB_BTAG_SIZE-1:0] i0_predict_btag_d, // DEC predict branch tag output logic [$clog2(pt.BTB_SIZE)-1:0] dec_fa_error_index, // Fully associt btb error index output logic dec_lsu_valid_raw_d, output logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control output logic [1:0] dec_data_en, // clock-gate control logic output logic [1:0] dec_ctl_en, input logic [15:0] ifu_i0_cinst, // 16b compressed instruction output el2_trace_pkt_t trace_rv_trace_pkt, // trace packet // PMP signals output el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES], output logic [31:0] pmp_pmpaddr[pt.PMP_ENTRIES], `ifdef RV_USER_MODE // Privilege mode output logic priv_mode, output logic priv_mode_eff, output logic priv_mode_ns, // mseccfg CSR content for PMP output el2_mseccfg_pkt_t mseccfg, `endif // feature disable from mfdc output logic dec_tlu_external_ldfwd_disable, // disable external load forwarding output logic dec_tlu_sideeffect_posted_disable, // disable posted stores to side-effect address output logic dec_tlu_core_ecc_disable, // disable core ECC output logic dec_tlu_bpred_disable, // disable branch prediction output logic dec_tlu_wb_coalescing_disable, // disable writebuffer coalescing output logic [2:0] dec_tlu_dma_qos_prty, // DMA QoS priority coming from MFDC [18:16] // clock gating overrides from mcgc output logic dec_tlu_misc_clk_override, // override misc clock domain gating output logic dec_tlu_ifu_clk_override, // override fetch clock domain gating output logic dec_tlu_lsu_clk_override, // override load/store clock domain gating output logic dec_tlu_bus_clk_override, // override bus clock domain gating output logic dec_tlu_pic_clk_override, // override PIC clock domain gating output logic dec_tlu_picio_clk_override, // override PICIO clock domain gating output logic dec_tlu_dccm_clk_override, // override DCCM clock domain gating output logic dec_tlu_icm_clk_override, // override ICCM clock domain gating output logic dec_tlu_i0_commit_cmt, // committed i0 instruction // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode // Flop scan mode control /*pragma coverage on*/ ); el2_br_pkt_t i0_brp; // branch packet el2_lsu_error_pkt_t lsu_error_pkt_r; // LSU exception/error packet el2_trigger_pkt_t [3:0] trigger_pkt_any; // Unwrap structure support both simulators for (genvar i = 0; i < 4; i++) begin : g_unwrap_el2_trigger_pkt_t assign trigger_pkt_any_select[i] = trigger_pkt_any[i][37]; assign trigger_pkt_any_match[i] = trigger_pkt_any[i][36]; assign trigger_pkt_any_store[i] = trigger_pkt_any[i][35]; assign trigger_pkt_any_load[i] = trigger_pkt_any[i][34]; assign trigger_pkt_any_execute[i] = trigger_pkt_any[i][33]; assign trigger_pkt_any_m[i] = trigger_pkt_any[i][32]; assign trigger_pkt_any_tdata2[i] = trigger_pkt_any[i][31:0]; end assign i0_brp = '0; assign lsu_error_pkt_r = '0; el2_dec dut (.*); endmodule ================================================ FILE: verification/block/dec/test_dec.py ================================================ # Copyright (c) 2025 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from pyuvm import ConfigDB from testbench import BaseEnv, BaseTest, DecSequence # ============================================================================= class DecTluCtlTest(BaseTest): def __init__(self, test_name, name, parent, env_class=BaseEnv): self.test_name = test_name super().__init__(name, parent, env_class) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() ConfigDB().set(None, "*", "TEST", self.test_name) self.seq = DecSequence("stimulus") async def run(self): await self.seq.start(self.env.dec_seqr) @pyuvm.test() class TestMeihap(DecTluCtlTest): def __init__(self, name, parent, env_class=BaseEnv): super().__init__("meihap", name, parent, env_class) @pyuvm.test() class TestMtdata(DecTluCtlTest): def __init__(self, name, parent, env_class=BaseEnv): super().__init__("mtdata", name, parent, env_class) @pyuvm.test() class TestCsrAccess(DecTluCtlTest): def __init__(self, name, parent, env_class=BaseEnv): super().__init__("csr_access", name, parent, env_class) @pyuvm.test() class TestDebugICCache(DecTluCtlTest): def __init__(self, name, parent, env_class=BaseEnv): super().__init__("debug_ic_cache", name, parent, env_class) @pyuvm.test() class TestDebugCSRs(DecTluCtlTest): def __init__(self, name, parent, env_class=BaseEnv): super().__init__("debug_csrs_access", name, parent, env_class) @pyuvm.test() class TestMeicidpl(DecTluCtlTest): def __init__(self, name, parent, env_class=BaseEnv): super().__init__("meicidpl", name, parent, env_class) ================================================ FILE: verification/block/dec/testbench.py ================================================ # Copyright (c) 2025 Antmicro # SPDX-License-Identifier: Apache-2.0 import logging import os import random from dataclasses import dataclass from enum import IntEnum import cocotb import csrs from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge from csrs import get_bit from pyuvm import ( ConfigDB, uvm_analysis_port, uvm_component, uvm_driver, uvm_env, uvm_get_port, uvm_report_object, uvm_sequence, uvm_sequence_item, uvm_sequencer, uvm_test, uvm_tlm_analysis_fifo, ) # ============================================================================== @dataclass class TriggerAnyPktT: select: int = 0 match: int = 0 store: int = 0 load: int = 0 execute: int = 0 m: int = 0 tdata2: int = 0 @staticmethod def get_from_dut(dut): trigger_pkt_any_select = int(dut.trigger_pkt_any_select.value) trigger_pkt_any_match = int(dut.trigger_pkt_any_match.value) trigger_pkt_any_store = int(dut.trigger_pkt_any_store.value) trigger_pkt_any_load = int(dut.trigger_pkt_any_load.value) trigger_pkt_any_execute = int(dut.trigger_pkt_any_execute.value) trigger_pkt_any_m = int(dut.trigger_pkt_any_m.value) trigger_pkt_any_tdata2 = int(dut.trigger_pkt_any_tdata2.value) return TriggerAnyPktT( trigger_pkt_any_select, trigger_pkt_any_match, trigger_pkt_any_store, trigger_pkt_any_load, trigger_pkt_any_execute, trigger_pkt_any_m, trigger_pkt_any_tdata2, ) def log_mismatch_error(logger, name, expected, got): logger.error(f"{name} {hex(expected)} != {hex(got)} (should be {hex(expected)})") csr_list = [getattr(csrs, mod) for mod in dir(csrs) if isinstance(getattr(csrs, mod), csrs.CSR)] CSR_OPCODE = 0b1110011 class Funct3(IntEnum): CSRRW = 0b001 CSRRS = 0b010 CSRRC = 0b011 CSRRWI = 0b101 CSRRSI = 0b110 CSRRCI = 0b111 def csr_access_inst(csr, rs1, funct3, rd, opcode): csr_mask = (1 << 13) - 1 rs1_mask = (1 << 6) - 1 funct3_mask = (1 << 4) - 1 rd_mask = (1 << 6) - 1 opcode_mask = (1 << 8) - 1 return ( (csr & csr_mask) << 20 | (rs1 & rs1_mask) << 15 | (funct3 & funct3_mask) << 12 | (rd & rd_mask) << 7 | (opcode & opcode_mask) ) @dataclass class ReadCSRInst: csr: int = 0 funct3: Funct3 = Funct3.CSRRS def encode(self): return csr_access_inst(self.csr, 0, self.funct3, 0, CSR_OPCODE) @dataclass class WriteCSRInst: csr: int = 0 funct3: Funct3 = Funct3.CSRRW def encode(self): return csr_access_inst(self.csr, 0, self.funct3, 0, CSR_OPCODE) def randint(width=32): return random.randint(0, 2 ** (width) - 1) class DecInputItem(uvm_sequence_item): """ Trigger Logic input data """ def __init__( self, pic_pl=0, pic_claimid=0, exu_i0_result_x=0, ifu_ic_debug_rd_data=0, csrw_instr=0, csrr_instr=0, csr_addr=0, mtdata1=0, mtdata2=0, mtsel=0, ): super().__init__("DecInputItem") self.exu_i0_result_x = exu_i0_result_x self.csr_addr = csr_addr self.csrw_instr = csrw_instr self.csrr_instr = csrr_instr self.pic_pl = pic_pl self.pic_claimid = pic_claimid self.ifu_ic_debug_rd_data = ifu_ic_debug_rd_data self.mtdata1 = mtdata1 self.mtdata2 = mtdata2 self.mtsel = mtsel def randomize(self, test): if test == "meihap": self.pic_claimid = randint(8) self.exu_i0_result_x = randint(22) << 10 self.csr_addr = csrs.MEIVT self.csrw_instr = WriteCSRInst(self.csr_addr).encode() self.csrr_instr = ReadCSRInst(self.csr_addr).encode() elif test == "mtdata": # bits 31:28 are hardcoded to 0x2 mtdata1 = "0010" for _ in range(28): mtdata1 += random.choice(["0", "1"]) # set DMODE (bit 27) to 0 so that the settings are actually taken into account # in the list, bits are numbered from 0 tmp = list(mtdata1) tmp[31 - 27] = "0" mtdata1 = "".join(tmp) self.mtdata1 = int(mtdata1, 2) self.mtdata2 = randint(32) self.mtsel = randint(2) elif test == "csr_access": self.csr_addr = random.choice( [ csrs.MCOUNTINHIBIT, csrs.MDCCMECT, csrs.MEICURPL, csrs.MEIPT, csrs.MFDC, csrs.MFDHT, csrs.MHPMC3, csrs.MHPMC3H, csrs.MHPMC4, csrs.MHPMC4H, csrs.MHPMC5, csrs.MHPMC5H, csrs.MHPMC6, csrs.MHPMC6H, csrs.MHPME3, csrs.MHPME4, csrs.MHPME5, csrs.MHPME6, csrs.MICCMECT, csrs.MICECT, csrs.MINSTRETH, csrs.MINSTRETL, csrs.MRAC, csrs.MTVEC, ] ) self.exu_i0_result_x = randint() self.csrw_instr = WriteCSRInst(self.csr_addr).encode() self.csrr_instr = ReadCSRInst(self.csr_addr).encode() elif test == "debug_ic_cache": self.ifu_ic_debug_rd_data = randint(71) elif test == "debug_csrs_access": self.exu_i0_result_x = randint(32) self.csr_addr = random.choice( [csrs.DICAD0, csrs.DICAD0H, csrs.DICAWICS, csrs.DPC, csrs.DCSR] ) self.csrw_instr = WriteCSRInst(self.csr_addr).encode() self.csrr_instr = ReadCSRInst(self.csr_addr).encode() elif test == "meicidpl": self.pic_pl = randint(4) self.csr_addr = csrs.MEICIDPL self.csrw_instr = WriteCSRInst(self.csr_addr).encode() self.csrr_instr = ReadCSRInst(self.csr_addr).encode() class DecOutputItem(uvm_sequence_item): """ Trigger Logic output data """ def __init__( self, csrr_instr=0, dec_csr_wrdata_r=0, dec_csr_rddata_d=0, dec_tlu_meihap=0, trigger_pkt_any=TriggerAnyPktT(), ifu_ic_debug_rd_data=0, ): super().__init__("DecOutputItem") self.csrr_instr = csrr_instr self.dec_csr_wrdata_r = dec_csr_wrdata_r self.dec_csr_rddata_d = dec_csr_rddata_d self.dec_tlu_meihap = dec_tlu_meihap self.trigger_pkt_any = trigger_pkt_any self.ifu_ic_debug_rd_data = ifu_ic_debug_rd_data # ============================================================================== class DecDriver(uvm_driver): """ Trigger Logic driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def read_csr(self, instr): self.dut.ifu_i0_valid.value = 0 await RisingEdge(self.dut.clk) self.dut.ifu_i0_valid.value = 1 self.dut.ifu_i0_instr.value = instr await RisingEdge(self.dut.clk) self.dut.ifu_i0_valid.value = 0 self.dut.ifu_i0_instr.value = 0 async def write_csr(self, instr, data): self.dut.ifu_i0_valid.value = 0 await RisingEdge(self.dut.clk) self.dut.ifu_i0_valid.value = 1 self.dut.ifu_i0_instr.value = instr await RisingEdge(self.dut.clk) self.dut.ifu_i0_instr.value = 0 self.dut.exu_i0_result_x.value = data self.dut.ifu_i0_valid.value = 0 await RisingEdge(self.dut.clk) self.dut.exu_i0_result_x.value = 0 async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, DecInputItem): test = ConfigDB().get(self, "", "TEST") if test == "meihap": # Write MEIVT await self.write_csr(it.csrw_instr, it.exu_i0_result_x) await ClockCycles(self.dut.clk, 2) # Write pic_claimid via MEICPCT self.dut.pic_claimid.value = it.pic_claimid instr = WriteCSRInst(csrs.MEICPCT).encode() await self.write_csr(instr, it.exu_i0_result_x) # Allow output monitor to catch the data on the outputs await ClockCycles(self.dut.clk, 2) elif test == "mtdata": await self.write_csr(WriteCSRInst(csrs.MTSEL).encode(), it.mtsel) await self.write_csr(WriteCSRInst(csrs.MTDATA1).encode(), it.mtdata1) await self.write_csr(WriteCSRInst(csrs.MTDATA2).encode(), it.mtdata2) await ClockCycles(self.dut.clk, 4) elif test in ["csr_access"]: # Write CSR await self.write_csr(it.csrw_instr, it.exu_i0_result_x) await ClockCycles(self.dut.clk, 2) # Read the CSR back await self.read_csr(it.csrr_instr) await RisingEdge(self.dut.clk) elif test == "debug_ic_cache": self.dut.ifu_ic_debug_rd_data_valid.value = 1 self.dut.ifu_ic_debug_rd_data.value = it.ifu_ic_debug_rd_data await RisingEdge(self.dut.clk) self.dut.ifu_ic_debug_rd_data_valid.value = 0 await self.read_csr(ReadCSRInst(csrs.DICAD0).encode()) await self.read_csr(ReadCSRInst(csrs.DICAD0H).encode()) await self.read_csr(ReadCSRInst(csrs.DICAD1).encode()) elif test == "debug_csrs_access": await self.write_csr(it.csrw_instr, it.exu_i0_result_x) await ClockCycles(self.dut.clk, 2) await self.read_csr(it.csrr_instr) await ClockCycles(self.dut.clk, 2) elif test == "meicidpl": self.dut.pic_pl.value = it.pic_pl await self.write_csr(it.csrw_instr, 0) await ClockCycles(self.dut.clk, 2) await self.read_csr(it.csrr_instr) await RisingEdge(self.dut.clk) else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class DecInputMonitor(uvm_component): """ Monitor for Trigger Logic inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: test = ConfigDB().get(self, "", "TEST") if test == "meihap": await RisingEdge(self.dut.ifu_i0_valid) await ClockCycles(self.dut.clk, 2) exu_i0_result_x = int(self.dut.exu_i0_result_x.value) await RisingEdge(self.dut.ifu_i0_valid) pic_claimid = int(self.dut.pic_claimid.value) self.ap.write( DecInputItem(pic_claimid=pic_claimid, exu_i0_result_x=exu_i0_result_x) ) elif test == "mtdata": await RisingEdge(self.dut.ifu_i0_valid) await ClockCycles(self.dut.clk, 2) mtsel = int(self.dut.exu_i0_result_x.value) await RisingEdge(self.dut.ifu_i0_valid) await ClockCycles(self.dut.clk, 2) mtdata1 = int(self.dut.exu_i0_result_x.value) await RisingEdge(self.dut.ifu_i0_valid) await ClockCycles(self.dut.clk, 2) mtdata2 = int(self.dut.exu_i0_result_x.value) self.ap.write(DecInputItem(mtdata1=mtdata1, mtdata2=mtdata2, mtsel=mtsel)) elif test in ["csr_access"]: # Wait for CSR write await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) csrw_instr = int(self.dut.ifu_i0_instr.value) await RisingEdge(self.dut.clk) exu_i0_result_x = int(self.dut.exu_i0_result_x.value) # Wait for CSR read await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) csrr_instr = int(self.dut.ifu_i0_instr.value) self.ap.write( DecInputItem( csrw_instr=csrw_instr, csrr_instr=csrr_instr, exu_i0_result_x=exu_i0_result_x, ) ) elif test == "debug_ic_cache": # Wait for CSR write await RisingEdge(self.dut.ifu_ic_debug_rd_data_valid) await RisingEdge(self.dut.clk) ic_debug_rd_data = int(self.dut.ifu_ic_debug_rd_data.value) self.ap.write(DecInputItem(ifu_ic_debug_rd_data=ic_debug_rd_data)) # Wait for CSR reads await ClockCycles(self.dut.clk, 4) elif test == "debug_csrs_access": await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) csr_addr = int(self.dut.ifu_i0_instr.value) >> 20 await ClockCycles(self.dut.clk, 1) exu_i0_result_x = int(self.dut.exu_i0_result_x.value) # Await CSR read await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) self.ap.write(DecInputItem(csr_addr=csr_addr, exu_i0_result_x=exu_i0_result_x)) elif test == "meicidpl": await RisingEdge(self.dut.ifu_i0_valid) csr_addr = int(self.dut.ifu_i0_instr.value) >> 20 await ClockCycles(self.dut.clk, 2) exu_i0_result_x = int(self.dut.exu_i0_result_x.value) await RisingEdge(self.dut.ifu_i0_valid) self.ap.write(DecInputItem(csr_addr=csr_addr, exu_i0_result_x=exu_i0_result_x)) class DecOutputMonitor(uvm_component): """ Monitor for Trigger Logic outputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: test = ConfigDB().get(self, "", "TEST") if test == "meihap": for _ in range(2): await RisingEdge(self.dut.ifu_i0_valid) await ClockCycles(self.dut.clk, 4) dec_tlu_meihap = int(self.dut.dec_tlu_meihap.value) self.ap.write(DecOutputItem(dec_tlu_meihap=dec_tlu_meihap)) elif test == "mtdata": # Wait for CSR writes for _ in range(3): await RisingEdge(self.dut.ifu_i0_valid) # Wait for the outputs await ClockCycles(self.dut.clk, 4) trigger_pkt_any = TriggerAnyPktT.get_from_dut(self.dut) self.ap.write(DecOutputItem(trigger_pkt_any=trigger_pkt_any)) elif test in ["csr_access"]: for _ in range(2): await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) csrr_instr = int(self.dut.ifu_i0_instr.value) dec_csr_rddata_d = int(self.dut.dec_csr_rddata_d.value) self.ap.write( DecOutputItem( csrr_instr=csrr_instr, dec_csr_rddata_d=dec_csr_rddata_d, ) ) elif test == "debug_ic_cache": await RisingEdge(self.dut.ifu_ic_debug_rd_data_valid) await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) dicad0 = int(self.dut.dec_csr_rddata_d.value) await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) dicad0h = int(self.dut.dec_csr_rddata_d.value) await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) dicad1 = int(self.dut.dec_csr_rddata_d.value) ifu_ic_debug_rd_data = dicad0 | (dicad0h << 32) | (dicad1 << 64) self.ap.write(DecOutputItem(ifu_ic_debug_rd_data=ifu_ic_debug_rd_data)) elif test == "debug_csrs_access": for _ in range(2): await RisingEdge(self.dut.ifu_i0_valid) await RisingEdge(self.dut.clk) dec_csr_rddata_d = int(self.dut.dec_csr_rddata_d.value) self.ap.write(DecOutputItem(dec_csr_rddata_d=dec_csr_rddata_d)) elif test == "meicidpl": for _ in range(2): await RisingEdge(self.dut.ifu_i0_valid) csrr_instr = int(self.dut.ifu_i0_instr.value) await RisingEdge(self.dut.clk) dec_csr_rddata_d = int(self.dut.dec_csr_rddata_d.value) self.ap.write( DecOutputItem( csrr_instr=csrr_instr, dec_csr_rddata_d=dec_csr_rddata_d, ) ) # ============================================================================== class DecScoreboard(uvm_component): """ Trigger Logic scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): # noqa: C901 # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True test = ConfigDB().get(self, "", "TEST") if test == "meihap": pic_claimid_i = item_inp.pic_claimid pic_claimid_o = item_out.dec_tlu_meihap & 0xFF meivt_i = item_inp.exu_i0_result_x >> 12 meivt_o = item_out.dec_tlu_meihap >> 10 if pic_claimid_i != pic_claimid_o: log_mismatch_error(self.logger, "pic_claimid", pic_claimid_i, pic_claimid_o) self.passed = False if meivt_i != meivt_o: log_mismatch_error(self.logger, "meivt", meivt_i, meivt_o) self.passed = False elif test == "mtdata": tdata2_mask = 0xFFFFFFFF mtsel = item_inp.mtsel mtdata1_i = item_inp.mtdata1 mtdata2_i = item_inp.mtdata2 trigger_pkt_any = item_out.trigger_pkt_any select_i = get_bit(mtdata1_i, 19) match_i = get_bit(mtdata1_i, 7) store_i = get_bit(mtdata1_i, 1) load_i = get_bit(mtdata1_i, 0) & ~get_bit(mtdata1_i, 19) execute_i = get_bit(mtdata1_i, 2) & ~get_bit(mtdata1_i, 19) m_i = get_bit(mtdata1_i, 6) select_o = get_bit(trigger_pkt_any.select, mtsel) match_o = get_bit(trigger_pkt_any.match, mtsel) store_o = get_bit(trigger_pkt_any.store, mtsel) load_o = get_bit(trigger_pkt_any.load, mtsel) execute_o = get_bit(trigger_pkt_any.execute, mtsel) m_o = get_bit(trigger_pkt_any.m, mtsel) mtdata2_o = (trigger_pkt_any.tdata2 >> (mtsel * 32)) & tdata2_mask if mtdata2_i != mtdata2_o: log_mismatch_error(self.logger, "mtdata2", mtdata2_i, mtdata2_o) self.passed = False if select_i != select_o: log_mismatch_error(self.logger, "select", select_i, select_o) self.passed = False if match_i != match_o: log_mismatch_error(self.logger, "match", match_i, match_o) self.passed = False if store_i != store_o: log_mismatch_error(self.logger, "store", store_i, store_o) self.passed = False if load_i != load_o: log_mismatch_error(self.logger, "load", load_i, load_o) self.passed = False if execute_i != execute_o: log_mismatch_error(self.logger, "execute", execute_i, execute_o) self.passed = False if m_i != m_o: log_mismatch_error(self.logger, "m", m_i, m_o) self.passed = False elif test == "csr_access": i0 = item_inp.csrw_instr i1 = item_inp.csrr_instr wr_addr = (i0 >> 20) & ((1 << 13) - 1) rd_addr = (i1 >> 20) & ((1 << 13) - 1) if wr_addr != rd_addr: err_msg = f"Write to reg[{hex(wr_addr)}] but read from reg[{hex(rd_addr)}]" self.logger.error(err_msg) self.passed = False csr = rd_addr data_in = item_inp.exu_i0_result_x data_out = item_out.dec_csr_rddata_d for c in csr_list: if c == csr: data_in = c.out(data_in) break if data_in != data_out: log_mismatch_error(self.logger, f"reg_val[{hex(csr)}]", data_in, data_out) self.passed = False elif test == "debug_ic_cache": ifu_ic_debug_rd_data_in = item_inp.ifu_ic_debug_rd_data ifu_ic_debug_rd_data_out = item_out.ifu_ic_debug_rd_data if ifu_ic_debug_rd_data_in != ifu_ic_debug_rd_data_out: log_mismatch_error( self.logger, "read_data", ifu_ic_debug_rd_data_in, ifu_ic_debug_rd_data_out ) self.passed = False elif test == "debug_csrs_access": csr = item_inp.csr_addr reg_val_i = item_inp.exu_i0_result_x reg_val_o = item_out.dec_csr_rddata_d dbg_csrs = [csrs.DICAD0, csrs.DICAD0H, csrs.DICAWICS, csrs.DPC, csrs.DCSR] for c in dbg_csrs: if c == csr: reg_val_i = c.out(reg_val_i) break if reg_val_i != reg_val_o: log_mismatch_error(self.logger, f"reg_val[{hex(csr)}]", reg_val_i, reg_val_o) self.passed = False elif test == "meicidpl": reg_val_i = item_inp.exu_i0_result_x reg_val_o = item_out.dec_csr_rddata_d reg_val_i = csrs.MEICIDPL.out(reg_val_i) if reg_val_i != reg_val_o: log_mismatch_error(self.logger, f"reg_val[{hex(csr)}]", reg_val_i, reg_val_o) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class DecSequence(uvm_sequence): def __init__(self, name, ops=None): super().__init__(name) async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") test = ConfigDB().get(None, "", "TEST") for _ in range(count): item = DecInputItem() item.randomize(test) await self.start_item(item) await self.finish_item(item) # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 5000) # Sequencers self.dec_seqr = uvm_sequencer("dec_seqr", self) # Driver self.dec_drv = DecDriver("dec_drv", self, dut=cocotb.top) # Monitors self.inp_mon = DecInputMonitor("inp_mon", self, dut=cocotb.top) self.out_mon = DecOutputMonitor("out_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = DecScoreboard("scoreboard", self) def connect_phase(self): self.dec_drv.seq_item_port.connect(self.dec_seqr.seq_item_export) self.inp_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.out_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def enter_debug_mode(self): cocotb.top.dbg_halt_req.value = 1 await ClockCycles(cocotb.top.clk, 2) cocotb.top.dbg_halt_req.value = 0 if not cocotb.top.o_debug_mode_status.value: await RisingEdge(cocotb.top.o_debug_mode_status) async def do_reset(self): cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): test = ConfigDB().get(self, "", "TEST") self.raise_objection() # Start clocks self.start_clock("clk") self.start_clock("active_clk") self.start_clock("free_clk") self.start_clock("free_l2clk") # Enable run after reset cocotb.top.mpc_reset_run_req.value = 1 # Drive status indicators of non-included modules cocotb.top.lsu_idle_any.value = 1 cocotb.top.ifu_miss_state_idle.value = 1 cocotb.top.lsu_fastint_stall_any.value = 0 cocotb.top.rst_vec.value = 0 cocotb.top.nmi_int.value = 0 cocotb.top.nmi_vec.value = 0 cocotb.top.i_cpu_halt_req.value = 0 cocotb.top.i_cpu_run_req.value = 0 cocotb.top.core_id.value = 0 cocotb.top.mpc_debug_halt_req.value = 0 cocotb.top.mpc_debug_run_req.value = 0 cocotb.top.exu_pmu_i0_br_misp.value = 0 cocotb.top.exu_pmu_i0_br_ataken.value = 0 cocotb.top.exu_pmu_i0_pc4.value = 0 cocotb.top.lsu_nonblock_load_valid_m.value = 0 cocotb.top.lsu_nonblock_load_tag_m.value = 0 cocotb.top.lsu_nonblock_load_inv_r.value = 0 cocotb.top.lsu_nonblock_load_inv_tag_r.value = 0 cocotb.top.lsu_nonblock_load_data_valid.value = 0 cocotb.top.lsu_nonblock_load_data_error.value = 0 cocotb.top.lsu_nonblock_load_data_tag.value = 0 cocotb.top.lsu_nonblock_load_data.value = 0 cocotb.top.lsu_pmu_bus_trxn.value = 0 cocotb.top.lsu_pmu_bus_misaligned.value = 0 cocotb.top.lsu_pmu_bus_error.value = 0 cocotb.top.lsu_pmu_bus_busy.value = 0 cocotb.top.lsu_pmu_misaligned_m.value = 0 cocotb.top.lsu_pmu_load_external_m.value = 0 cocotb.top.lsu_pmu_store_external_m.value = 0 cocotb.top.dma_pmu_dccm_read.value = 0 cocotb.top.dma_pmu_dccm_write.value = 0 cocotb.top.dma_pmu_any_read.value = 0 cocotb.top.dma_pmu_any_write.value = 0 cocotb.top.lsu_fir_addr.value = 0 cocotb.top.lsu_fir_error.value = 0 cocotb.top.ifu_pmu_instr_aligned.value = 0 cocotb.top.ifu_pmu_fetch_stall.value = 0 cocotb.top.ifu_pmu_ic_miss.value = 0 cocotb.top.ifu_pmu_ic_hit.value = 0 cocotb.top.ifu_pmu_bus_error.value = 0 cocotb.top.ifu_pmu_bus_busy.value = 0 cocotb.top.ifu_pmu_bus_trxn.value = 0 cocotb.top.ifu_ic_error_start.value = 0 cocotb.top.ifu_iccm_rd_ecc_single_err.value = 0 cocotb.top.lsu_trigger_match_m.value = 0 cocotb.top.dbg_cmd_valid.value = 0 cocotb.top.dbg_cmd_write.value = 0 cocotb.top.dbg_cmd_type.value = 0 cocotb.top.dbg_cmd_addr.value = 0 cocotb.top.dbg_cmd_wrdata.value = 0 cocotb.top.ifu_i0_icaf.value = 0 cocotb.top.ifu_i0_icaf_type.value = 0 cocotb.top.ifu_i0_icaf_second.value = 0 cocotb.top.ifu_i0_dbecc.value = 0 cocotb.top.ifu_i0_bp_index.value = 0 cocotb.top.ifu_i0_bp_fghr.value = 0 cocotb.top.ifu_i0_bp_btag.value = 0 cocotb.top.ifu_i0_fa_index.value = 0 cocotb.top.lsu_single_ecc_error_incr.value = 0 cocotb.top.lsu_imprecise_error_load_any.value = 0 cocotb.top.lsu_imprecise_error_store_any.value = 0 cocotb.top.lsu_imprecise_error_addr_any.value = 0 cocotb.top.exu_div_result.value = 0 cocotb.top.exu_div_wren.value = 0 cocotb.top.exu_csr_rs1_x.value = 0 cocotb.top.lsu_result_m.value = 0 cocotb.top.lsu_result_corr_r.value = 0 cocotb.top.lsu_load_stall_any.value = 0 cocotb.top.lsu_store_stall_any.value = 0 cocotb.top.dma_dccm_stall_any.value = 0 cocotb.top.dma_iccm_stall_any.value = 0 cocotb.top.iccm_dma_sb_error.value = 0 cocotb.top.exu_flush_final.value = 0 cocotb.top.exu_npc_r.value = 0 cocotb.top.exu_i0_result_x.value = 0 cocotb.top.ifu_i0_valid.value = 0 cocotb.top.ifu_i0_instr.value = 0 cocotb.top.ifu_i0_pc.value = 0 cocotb.top.ifu_i0_pc4.value = 0 cocotb.top.exu_i0_pc_x.value = 0 cocotb.top.mexintpend.value = 0 cocotb.top.timer_int.value = 0 cocotb.top.soft_int.value = 0 cocotb.top.pic_claimid.value = 0 cocotb.top.pic_pl.value = 0 cocotb.top.mhwakeup.value = 0 cocotb.top.ifu_ic_debug_rd_data.value = 0 cocotb.top.ifu_ic_debug_rd_data_valid.value = 0 cocotb.top.dbg_halt_req.value = 0 cocotb.top.dbg_resume_req.value = 0 cocotb.top.exu_i0_br_hist_r.value = 0 cocotb.top.exu_i0_br_error_r.value = 0 cocotb.top.exu_i0_br_start_error_r.value = 0 cocotb.top.exu_i0_br_valid_r.value = 0 cocotb.top.exu_i0_br_mp_r.value = 0 cocotb.top.exu_i0_br_middle_r.value = 0 cocotb.top.exu_i0_br_way_r.value = 0 cocotb.top.ifu_i0_cinst.value = 0 # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) if test == "debug_csrs_access": await self.enter_debug_mode() # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/dec_ib/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_dec_ib_ctl_wrapper VERILOG_SOURCES = \ $(TEST_DIR)/el2_dec_ib_ctl_wrapper.sv \ $(SRCDIR)/dec/el2_dec_ib_ctl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/dec_ib/config.vlt ================================================ `verilator_config lint_off -rule WIDTHTRUNC -file "*/el2_dec_ib_ctl_wrapper.sv" ================================================ FILE: verification/block/dec_ib/el2_dec_ib_ctl_wrapper.sv ================================================ // Copyright (c) 2024 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_dec_ib_ctl_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic dbg_cmd_valid, // valid dbg cmd input logic dbg_cmd_write, // dbg cmd is write input logic [ 1:0] dbg_cmd_type, // dbg type input logic [31:0] dbg_cmd_addr, // expand to 31:0 // Unpacked input el2_br_pkt_t i0_brp // i0 branch packet from aligner input logic i0_brp_valid, input logic [11:0] i0_brp_toffset, input logic [1:0] i0_brp_hist, input logic i0_brp_br_error, input logic i0_brp_br_start_error, input logic i0_brp_bank, input logic [31:1] i0_brp_prett, // predicted ret target input logic i0_brp_way, input logic i0_brp_ret, input logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] ifu_i0_bp_index, // BP index input logic [ pt.BHT_GHR_SIZE-1:0] ifu_i0_bp_fghr, // BP FGHR input logic [ pt.BTB_BTAG_SIZE-1:0] ifu_i0_bp_btag, // BP tag input logic [ $clog2(pt.BTB_SIZE)-1:0] ifu_i0_fa_index, // Fully associt btb index input logic ifu_i0_pc4, // i0 is 4B inst else 2B input logic ifu_i0_valid, // i0 valid from ifu input logic ifu_i0_icaf, // i0 instruction access fault input logic [1:0] ifu_i0_icaf_type, // i0 instruction access fault type input logic ifu_i0_icaf_second, // i0 has access fault on second 2B of 4B inst input logic ifu_i0_dbecc, // i0 double-bit error input logic [31:0] ifu_i0_instr, // i0 instruction from the aligner input logic [31:1] ifu_i0_pc, // i0 pc from the aligner output logic dec_ib0_valid_d, // ib0 valid output logic dec_debug_valid_d, // Debug read or write at D-stage output logic [31:0] dec_i0_instr_d, // i0 inst at decode output logic [31:1] dec_i0_pc_d, // i0 pc at decode output logic dec_i0_pc4_d, // i0 is 4B inst else 2B // Unpacked output el2_br_pkt_t dec_i0_brp // i0 branch packet at decode output logic dec_i0_brp_valid, output logic [11:0] dec_i0_brp_toffset, output logic [1:0] dec_i0_brp_hist, output logic dec_i0_brp_br_error, output logic dec_i0_brp_br_start_error, output logic dec_i0_brp_bank, output logic [31:1] dec_i0_brp_prett, // predicted ret target output logic dec_i0_brp_way, output logic dec_i0_brp_ret, output logic [pt.BTB_ADDR_HI:pt.BTB_ADDR_LO] dec_i0_bp_index, // i0 branch index output logic [ pt.BHT_GHR_SIZE-1:0] dec_i0_bp_fghr, // BP FGHR output logic [ pt.BTB_BTAG_SIZE-1:0] dec_i0_bp_btag, // BP tag output logic [ $clog2(pt.BTB_SIZE)-1:0] dec_i0_bp_fa_index, // Fully associt btb index output logic dec_i0_icaf_d, // i0 instruction access fault at decode output logic dec_i0_icaf_second_d, // i0 instruction access fault on second 2B of 4B inst output logic [1:0] dec_i0_icaf_type_d, // i0 instruction access fault type output logic dec_i0_dbecc_d, // i0 double-bit error at decode output logic dec_debug_wdata_rs1_d, // put debug write data onto rs1 source: machine is halted output logic dec_debug_fence_d // debug fence inst ); el2_br_pkt_t i0_brp; el2_br_pkt_t dec_i0_brp; assign i0_brp.valid = i0_brp_valid; assign i0_brp.toffset = i0_brp_toffset; assign i0_brp.hist = i0_brp_hist; assign i0_brp.br_error = i0_brp_br_error; assign i0_brp.br_start_error = i0_brp_br_start_error; assign i0_brp.bank = i0_brp_bank; assign i0_brp.prett = i0_brp_prett; assign i0_brp.way = i0_brp_way; assign i0_brp.ret = i0_brp_ret; assign dec_i0_brp_valid = dec_i0_brp.valid; assign dec_i0_brp_toffset = dec_i0_brp.toffset; assign dec_i0_brp_hist = dec_i0_brp.hist; assign dec_i0_brp_br_error = dec_i0_brp.br_error; assign dec_i0_brp_br_start_error = dec_i0_brp.br_start_error; assign dec_i0_brp_bank = dec_i0_brp.bank; assign dec_i0_brp_prett = dec_i0_brp.prett; assign dec_i0_brp_way = dec_i0_brp.way; assign dec_i0_brp_ret = dec_i0_brp.ret; // The trigger unit el2_dec_ib_ctl tu (.*); endmodule ================================================ FILE: verification/block/dec_ib/test_dec_ib.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseTest, IbCtlSequence # ============================================================================= @pyuvm.test() class TestIbCtlLogic(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = IbCtlSequence("stimulus") async def run_phase(self): self.raise_objection() # Run the actual test await self.run() self.drop_objection() async def run(self): await self.seq.start(self.env.seqr) ================================================ FILE: verification/block/dec_ib/testbench.py ================================================ # Copyright (c) 2024 Antmicro # SPDX-License-Identifier: Apache-2.0 import copy import math import os import random import struct import subprocess import textwrap from dataclasses import dataclass import pyuvm from cocotb.binary import BinaryValue from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from cocotb.types import Array, Range from pyuvm import * # ============================================================================== def get_opcode(asm_line, ext="rv32i_zicsr", size=32): """ Generates opcode int based on a line of assembly """ cmd = f"echo '{asm_line}' | riscv64-unknown-elf-as -march={ext} -o /dev/null -al | tail -n 1" # Take instruction hex (3rd column) and change its endianess out = subprocess.check_output([cmd], shell=True).decode().split()[2] out = "".join(textwrap.wrap(out, 2)[::-1]) assert len(out) == size // 4, f"instruction '{asm_line}' assembled to unexpected width" return int(out, 16) class DebugCmdType(IntEnum): GPR = 0 CSR = 1 MEMORY = 2 @dataclass class DebugCmd: write: int type: DebugCmdType addr: int class IbCtlInputItem(uvm_sequence_item): def __init__(self, debug_cmd, ifu_instr): super().__init__("IbCtlInputItem") self.debug_cmd = debug_cmd self.ifu_instr = ifu_instr @property def debug_instr(self): if self.debug_cmd.type == DebugCmdType.GPR: if self.debug_cmd.write: return get_opcode(f"or x{self.debug_cmd.addr}, x0, x0") else: return get_opcode(f"or x0, x{self.debug_cmd.addr}, x0") elif self.debug_cmd.type == DebugCmdType.CSR: if self.debug_cmd.write: return get_opcode(f"csrrw x0, {self.debug_cmd.addr}, x0") else: return get_opcode(f"csrrs x0, {self.debug_cmd.addr}, x0") return 0 class IbCtlOutputItem(uvm_sequence_item): def __init__(self, instr): self.instr = instr super().__init__("IbCtlOutputItem") # ============================================================================== class IbCtlDriver(uvm_driver): def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: item = await self.seq_item_port.get_next_item() self.dut.dbg_cmd_valid.value = 1 self.dut.dbg_cmd_write.value = item.debug_cmd.write self.dut.dbg_cmd_type.value = int(item.debug_cmd.type) self.dut.dbg_cmd_addr.value = item.debug_cmd.addr self.dut.ifu_i0_instr.value = item.ifu_instr await Timer(period, "ns") self.seq_item_port.item_done() class IbCtlInputMonitor(uvm_component): def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: # Wait for the driver to set the input signals await Timer(period, "ns") write = int(self.dut.dbg_cmd_write.value) type = int(self.dut.dbg_cmd_type.value) addr = int(self.dut.dbg_cmd_addr.value) ifu_instr = int(self.dut.ifu_i0_instr.value) self.ap.write(IbCtlInputItem(DebugCmd(write, DebugCmdType(type), addr), ifu_instr)) class IbCtlOutputMonitor(uvm_component): """ Monitor for Trigger Logic outputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: # Wait for the driver to set the input signals await Timer(period, "ns") instr = int(self.dut.dec_i0_instr_d.value) self.ap.write(IbCtlOutputItem(instr)) # ============================================================================== class IbCtlScoreboard(uvm_component): def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True if item_inp.debug_instr != item_out.instr: self.logger.error(f"Expected {item_inp.debug_instr:08x} got {item_out.instr:08x}") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class IbCtlSequence(uvm_sequence): def __init__(self, name, ops=None): super().__init__(name) async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") for i in range(count): write = random.randint(0, 1) type = random.choice([DebugCmdType.GPR, DebugCmdType.CSR]) if type == DebugCmdType.GPR: addr = random.randrange(2**5) elif type == DebugCmdType.CSR: addr = random.randrange(2**12) debug_cmd = DebugCmd( write=write, type=type, addr=addr, ) ifu_instr = random.randrange(2**31) item = IbCtlInputItem(debug_cmd, ifu_instr) await self.start_item(item) await self.finish_item(item) # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 1000) # Sequencers self.seqr = uvm_sequencer("seqr", self) # Driver self.drv = IbCtlDriver("drv", self, dut=cocotb.top) # Monitors self.inp_mon = IbCtlInputMonitor("inp_mon", self, dut=cocotb.top) self.out_mon = IbCtlOutputMonitor("out_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = IbCtlScoreboard("scoreboard", self) def connect_phase(self): self.drv.seq_item_port.connect(self.seqr.seq_item_export) self.inp_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.out_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/dec_pmp_ctl/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_dec_tlu_ctl PMP_TEST := 1 CM_FILE = cm.cfg EXTRA_ARGS = -I$(SRCDIR)/include/ VERILOG_SOURCES = \ $(SRCDIR)/dec/el2_dec_tlu_ctl.sv \ $(SRCDIR)/dec/el2_dec_pmp_ctl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/dec_pmp_ctl/cm.cfg ================================================ +tree el2_dec_tlu_ctl ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node el2_dec_tlu_ctl.dcsr[14] -node el2_dec_tlu_ctl.dcsr[9] -node el2_dec_tlu_ctl.dcsr[5:4] -node el2_dec_tlu_ctl.dcsr_ns[14] -node el2_dec_tlu_ctl.dcsr_ns[9] -node el2_dec_tlu_ctl.dcsr_ns[5:4] -node el2_dec_tlu_ctl.ifu_mscause[2] -node el2_dec_tlu_ctl.mcgc[6] -node el2_dec_tlu_ctl.mcgc_int[6] -node el2_dec_tlu_ctl.mcgc_ns[6] -node el2_dec_tlu_ctl.mcountinhibit[1] -node el2_dec_tlu_ctl.mepc_rf[0] -node el2_dec_tlu_ctl.mie_rf[31] -node el2_dec_tlu_ctl.mie_rf[27:12] -node el2_dec_tlu_ctl.mie_rf[10:8] -node el2_dec_tlu_ctl.mie_rf[6:4] -node el2_dec_tlu_ctl.mie_rf[2:0] -node el2_dec_tlu_ctl.mip_rf[27:12] -node el2_dec_tlu_ctl.mip_rf[10:8] -node el2_dec_tlu_ctl.mip_rf[6:4] -node el2_dec_tlu_ctl.mip_rf[2:0] -node el2_dec_tlu_ctl.mstatus_rf[31:17] -node el2_dec_tlu_ctl.mstatus_rf[15:12] -node el2_dec_tlu_ctl.mstatus_rf[10:8] -node el2_dec_tlu_ctl.mstatus_rf[6:4] -node el2_dec_tlu_ctl.mstatus_rf[2:0] -node el2_dec_tlu_ctl.mtdata1_tsel_out[26] -node el2_dec_tlu_ctl.mtdata1_tsel_out[18:13] -node el2_dec_tlu_ctl.mtdata1_tsel_out[10:8] -node el2_dec_tlu_ctl.mtdata1_tsel_out[5:3] -node el2_dec_tlu_ctl.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node el2_dec_tlu_ctl.pmp.*pmpcfg_ff.din[6:5] -node el2_dec_tlu_ctl.pmp.*pmpcfg_ff.dout[6:5] -node el2_dec_tlu_ctl.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node el2_dec_tlu_ctl.pmp.pmp_pmpcfg_rddata[30:29] -node el2_dec_tlu_ctl.pmp.pmp_pmpcfg_rddata[22:21] -node el2_dec_tlu_ctl.pmp.pmp_pmpcfg_rddata[14:13] -node el2_dec_tlu_ctl.pmp.pmp_pmpcfg_rddata[6:5] ================================================ FILE: verification/block/dec_pmp_ctl/test_dec_pmp_ctl.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import ( PMPADDR0, PMPADDR16, PMPADDR32, PMPADDR48, PMPCFG, BaseTest, InputItem, ) # ============================================================================= class CsrSequence(uvm_sequence): """ A random sequence of PMP CSR items with random addresses and data """ def __init__(self, name): super().__init__(name) # Generate self.items = [] addrs = set() for i in range(5): while True: item = InputItem(PMPCFG) item.randomize() if item.addr not in addrs: break self.legalize_pmpcfg(item) self.items.append(item) addrs.add(item.addr) for base in [PMPADDR0, PMPADDR16, PMPADDR32, PMPADDR48]: while True: item = InputItem(base) item.randomize() if item.addr not in addrs: break self.legalize_pmpaddr(item) self.items.append(item) addrs.add(item.addr) def legalize_pmpcfg(self, item): """ Leave only A, X and R fields as any combination of them is leagal and does not influence PMPADDR access. Setting L would interfere with the test. """ mask = 0b00011101 item.data &= (mask << 24) | (mask << 16) | (mask << 8) | mask def legalize_pmpaddr(self, item): """ Mask out two MSBs """ item.data &= 0x3FFFFFFF async def body(self): # Run for item in self.items: await self.start_item(item) await self.finish_item(item) class PmpCfgLockSequence(uvm_sequence): """ A random sequence of PMPCFG accesses that also do entry locking """ def __init__(self, name): super().__init__(name) # Generate self.items = [] addrs = set() for i in range(10): while True: item = InputItem(PMPCFG) item.randomize() if item.addr not in addrs: break self.legalize_pmpcfg(item) self.items.append(item) addrs.add(item.addr) def legalize_pmpcfg(self, item): """ Leave only L, A, X and R fields as any combination of them is leagal and does not influence PMPADDR access. """ mask = 0b10011101 item.data &= (mask << 24) | (mask << 16) | (mask << 8) | mask async def body(self): # Run for item in self.items: await self.start_item(item) await self.finish_item(item) # ============================================================================= @pyuvm.test() class TestCsrAccess(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() count = ConfigDB().get(None, "", "TEST_ITERATIONS") self.seq = [CsrSequence("stimulus") for i in range(count)] async def run(self): for seq in self.seq: await seq.start(self.env.pmp_wr_seqr) await seq.start(self.env.pmp_rd_seqr) @pyuvm.test() class TestPmpCfgLock(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() count = ConfigDB().get(None, "", "TEST_ITERATIONS") self.seq = [PmpCfgLockSequence("stimulus") for i in range(count)] async def run(self): for seq in self.seq: # Do sequence of PMPCFG lock writes await seq.start(self.env.pmp_wr_seqr) await seq.start(self.env.pmp_rd_seqr) # Reset the module (there's no other way to clear the locks) await self.do_reset() ================================================ FILE: verification/block/dec_pmp_ctl/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import copy import math import os import random import struct import pyuvm from cocotb.binary import BinaryValue from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from cocotb.types import Array, Range from pyuvm import * # ============================================================================== PMPCFG = 0x3A0 PMPADDR0 = 0x3B0 PMPADDR16 = 0x3C0 PMPADDR32 = 0x3D0 PMPADDR48 = 0x3E0 # ============================================================================== class InputItem(uvm_sequence_item): """ PMP input item """ RANGE = 16 def __init__(self, addr=0, data=0): super().__init__("InputItem") self.addr = addr self.data = data def randomize(self): """ Randomize data and address offset """ self.addr += random.randint(0, self.RANGE - 1) self.data = random.randint(0, 0xFFFFFFFF) # ============================================================================== class CsrWriteDriver(uvm_driver): """ PMP CSR write port driver driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, InputItem): # Write await RisingEdge(self.dut.clk) self.dut.dec_csr_wen_r.value = 1 self.dut.dec_csr_wraddr_r.value = it.addr self.dut.dec_csr_wrdata_r.value = it.data await RisingEdge(self.dut.clk) self.dut.dec_csr_wen_r.value = 0 else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class CsrReadDriver(uvm_driver): """ PMP CSR read port driver driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, InputItem): # Read await RisingEdge(self.dut.clk) self.dut.dec_csr_rdaddr_d.value = it.addr await RisingEdge(self.dut.clk) self.dut.dec_csr_rdaddr_d.value = 0 else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() # ============================================================================== class WriteMonitor(uvm_component): """ Monitor for CSR write inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # A write to a CSR await RisingEdge(self.dut.clk) if self.dut.dec_csr_wen_r.value: addr = int(self.dut.dec_csr_wraddr_r) data = int(self.dut.dec_csr_wrdata_r) item = InputItem(addr, data) self.ap.write(item) class ReadMonitor(uvm_component): """ Monitor for CSR read inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # A read from a CSR await RisingEdge(self.dut.clk) addr = int(self.dut.dec_csr_rdaddr_d) & 0x3F0 if addr in [PMPCFG, PMPADDR0, PMPADDR16, PMPADDR32, PMPADDR48]: addr = int(self.dut.dec_csr_rdaddr_d) data = int(self.dut.dec_csr_rddata_d) item = InputItem(addr, data) self.ap.write(item) # ============================================================================== class Scoreboard(uvm_component): """ PMP dec ctl scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): self.passed = None # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True # Compare addresses and data if item_inp.addr != item_out.addr or item_inp.data != item_out.data: istr = f"{item_inp.addr:04X}:{item_inp.data:08X}" ostr = f"{item_out.addr:04X}:{item_out.data:08X}" self.logger.error(f"Mismatch {istr} vs. {ostr}") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 5000) # Sequencers self.pmp_wr_seqr = uvm_sequencer("pmp_wr_seqr", self) self.pmp_rd_seqr = uvm_sequencer("pmp_rd_seqr", self) # Drivers self.pmp_wr_drv = CsrWriteDriver("pmp_wr_drv", self, dut=cocotb.top) self.pmp_rd_drv = CsrReadDriver("pmp_rd_drv", self, dut=cocotb.top) # Monitors self.wr_mon = WriteMonitor("wr_mon", self, dut=cocotb.top) self.rd_mon = ReadMonitor("rd_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): self.pmp_wr_drv.seq_item_port.connect(self.pmp_wr_seqr.seq_item_export) self.pmp_rd_drv.seq_item_port.connect(self.pmp_rd_seqr.seq_item_export) self.wr_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.rd_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.rst_l.value = 0 cocotb.top.dec_csr_rdaddr_d.value = 0 cocotb.top.i_cpu_halt_req.value = 0 cocotb.top.i_cpu_run_req.value = 0 cocotb.top.lsu_fastint_stall_any.value = 0 cocotb.top.ifu_pmu_instr_aligned.value = 0 cocotb.top.ifu_pmu_fetch_stall.value = 0 cocotb.top.ifu_pmu_ic_miss.value = 0 cocotb.top.ifu_pmu_ic_hit.value = 0 cocotb.top.ifu_pmu_bus_error.value = 0 cocotb.top.ifu_pmu_bus_busy.value = 0 cocotb.top.ifu_pmu_bus_trxn.value = 0 cocotb.top.dec_pmu_instr_decoded.value = 0 cocotb.top.dec_pmu_decode_stall.value = 0 cocotb.top.dec_pmu_presync_stall.value = 0 cocotb.top.dec_pmu_postsync_stall.value = 0 cocotb.top.lsu_store_stall_any.value = 0 cocotb.top.dma_dccm_stall_any.value = 0 cocotb.top.dma_iccm_stall_any.value = 0 cocotb.top.exu_pmu_i0_br_misp.value = 0 cocotb.top.exu_pmu_i0_br_ataken.value = 0 cocotb.top.exu_pmu_i0_pc4.value = 0 cocotb.top.lsu_pmu_bus_trxn.value = 0 cocotb.top.lsu_pmu_bus_misaligned.value = 0 cocotb.top.lsu_pmu_bus_error.value = 0 cocotb.top.lsu_pmu_bus_busy.value = 0 cocotb.top.lsu_pmu_load_external_m.value = 0 cocotb.top.lsu_pmu_store_external_m.value = 0 cocotb.top.dma_pmu_dccm_read.value = 0 cocotb.top.dma_pmu_dccm_write.value = 0 cocotb.top.dma_pmu_any_read.value = 0 cocotb.top.dma_pmu_any_write.value = 0 cocotb.top.lsu_fir_addr.value = 0 cocotb.top.lsu_fir_error.value = 0 cocotb.top.iccm_dma_sb_error.value = 0 cocotb.top.lsu_single_ecc_error_incr.value = 0 cocotb.top.dec_pause_state.value = 0 cocotb.top.lsu_imprecise_error_store_any.value = 0 cocotb.top.lsu_imprecise_error_load_any.value = 0 cocotb.top.lsu_imprecise_error_addr_any.value = 0 cocotb.top.dec_csr_wen_unq_d.value = 0 cocotb.top.dec_csr_any_unq_d.value = 0 cocotb.top.dec_csr_rdaddr_d.value = 0 cocotb.top.dec_csr_wen_r.value = 0 cocotb.top.dec_csr_rdaddr_r.value = 0 cocotb.top.dec_csr_wraddr_r.value = 0 cocotb.top.dec_csr_wrdata_r.value = 0 cocotb.top.dec_csr_stall_int_ff.value = 0 cocotb.top.dec_tlu_i0_valid_r.value = 0 cocotb.top.exu_npc_r.value = 0 cocotb.top.dec_tlu_i0_pc_r.value = 0 cocotb.top.dec_illegal_inst.value = 0 cocotb.top.dec_i0_decode_d.value = 0 cocotb.top.exu_i0_br_hist_r.value = 0 cocotb.top.exu_i0_br_error_r.value = 0 cocotb.top.exu_i0_br_start_error_r.value = 0 cocotb.top.exu_i0_br_valid_r.value = 0 cocotb.top.exu_i0_br_mp_r.value = 0 cocotb.top.exu_i0_br_middle_r.value = 0 cocotb.top.exu_i0_br_way_r.value = 0 cocotb.top.dec_csr_stall_int_ff.value = 0 cocotb.top.dbg_halt_req.value = 0 cocotb.top.dbg_resume_req.value = 0 cocotb.top.lsu_idle_any.value = 0 cocotb.top.dec_div_active.value = 0 cocotb.top.ifu_ic_error_start.value = 0 cocotb.top.ifu_iccm_rd_ecc_single_err.value = 0 cocotb.top.ifu_ic_debug_rd_data.value = 0 cocotb.top.ifu_ic_debug_rd_data_valid.value = 0 cocotb.top.core_id.value = 0 await ClockCycles(cocotb.top.clk, 10) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") self.start_clock("free_clk") self.start_clock("csr_wr_clk") self.start_clock("free_l2clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/dec_tl/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_dec_trigger_wrapper VERILOG_SOURCES = \ $(TEST_DIR)/el2_dec_trigger_wrapper.sv \ $(SRCDIR)/dec/el2_dec_trigger.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/dec_tl/config.vlt ================================================ `verilator_config lint_off -rule WIDTHTRUNC -file "*/el2_dec_trigger_wrapper.sv" lint_off -rule UNUSEDPARAM -file "*/el2_dec_trigger_wrapper.sv" ================================================ FILE: verification/block/dec_tl/el2_dec_trigger_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_dec_trigger_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic [31:1] dec_i0_pc_d, // Unpacked [3:0] trigger_pkt_t input logic [3:0] select, input logic [3:0] match, input logic [3:0] store, input logic [3:0] load, input logic [3:0] execute, input logic [3:0] m, input logic [31:0] tdata[4], output logic [3:0] dec_i0_trigger_match_d ); // Pack triggers el2_trigger_pkt_t [3:0] trigger_pkt_any; for (genvar i = 0; i < 4; i++) begin : g_trigger_assigns assign trigger_pkt_any[i].select = select[i]; assign trigger_pkt_any[i].match = match[i]; assign trigger_pkt_any[i].store = store[i]; assign trigger_pkt_any[i].load = load[i]; assign trigger_pkt_any[i].execute = execute[i]; assign trigger_pkt_any[i].m = m[i]; assign trigger_pkt_any[i].tdata2 = tdata[i]; end // The trigger unit el2_dec_trigger tu ( .dec_i0_pc_d(dec_i0_pc_d[31:1]), .* ); endmodule ================================================ FILE: verification/block/dec_tl/test_dec_tl.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseTest, TlSequence # ============================================================================= @pyuvm.test() class TestTriggerLogic(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TlSequence("stimulus") async def run_phase(self): self.raise_objection() # Run the actual test await self.run() self.drop_objection() async def run(self): await self.seq.start(self.env.tl_seqr) ================================================ FILE: verification/block/dec_tl/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import copy import math import os import random import struct import pyuvm from cocotb.binary import BinaryValue from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from cocotb.types import Array, Range from pyuvm import * # ============================================================================== class TlInputItem(uvm_sequence_item): """ Trigger Logic output data """ def __init__(self, data=0, tdata=None, match=0): super().__init__("TlOutputItem") self.match = match self.data = data self.tdata = [None] * 4 if tdata is not None: for i in range(4): self.tdata[i] = tdata[i] def randomize(self): data = "" for i in range(31): # Sic. Last bit of PC is always 0 data += random.choice(["0", "1"]) data += "0" self.data = int(data, 2) self.match = 0 for i in range(4): matching = random.choice([False, True]) trigger = self.random_trigger(data, matching) self.match |= trigger["match"] << i self.tdata[i] = trigger["tdata"] def random_trigger(self, data, matching): """ Creates a trigger packet for data vector. It can be precised if the packet will be matching or not. """ # Select determines if we match against the PC or opcode, # TL in TLU does the first thing match = "" tdata = "" # Generate the matched part length = 0 if matching: length = random.randrange(32 + 1) if length > 0: tdata += data[:length] else: length = random.randrange(1, 32) for i in range(length): tdata += random.choice(["0", "1"]) # Assure a mismatch i = random.randrange(length) b = "1" if data[i] == "0" else "0" tdata = tdata[:i] + b + tdata[i + 1 :] # Generate the mask length = 32 - length if length == 0: match = "0" # Do full match else: match = "1" tdata += "0" + "1" * (length - 1) return {"match": int(match, 2), "tdata": int(tdata, 2)} class TlOutputItem(uvm_sequence_item): """ Trigger Logic output data """ def __init__(self, matches): super().__init__("TlOutputItem") self.matches = matches # ============================================================================== class TlDriver(uvm_driver): """ Trigger Logic driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: it = await self.seq_item_port.get_next_item() if isinstance(it, TlInputItem): self.dut.dec_i0_pc_d.value = it.data >> 1 for i in range(4): self.dut.tdata[i].value = it.tdata[i] self.dut.match.value = it.match self.dut.select.value = 0b0000 self.dut.store.value = 0b1111 self.dut.load.value = 0b1111 self.dut.execute.value = 0b1111 self.dut.m.value = 0b1111 # Wait for monitors to read the values await Timer(period, "ns") else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class TlInputMonitor(uvm_component): """ Monitor for Trigger Logic inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: # Wait for the driver to set the input signals await Timer(period, "ns") data = int(self.dut.dec_i0_pc_d.value) tdata = [None] * 4 for i in range(4): tdata[i] = int(self.dut.tdata[i].value) match = int(self.dut.match.value) self.ap.write(TlInputItem(data, tdata, match)) class TlOutputMonitor(uvm_component): """ Monitor for Trigger Logic outputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: # Wait for the driver to set the input signals await Timer(period, "ns") matches = int(self.dut.dec_i0_trigger_match_d.value) self.ap.write(TlOutputItem(matches)) # ============================================================================== class TlScoreboard(uvm_component): """ Trigger Logic scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True # Change outputs to str and reproduce what TL does res = 0 match = item_inp.match data = f"{item_inp.data:031b}" for i in range(4): tdata = f"{item_inp.tdata[i] >> 1:031b}" if match & (1 << i): length = tdata.rindex("0") res |= (tdata[:length] == data[:length]) << i else: res |= (tdata == data) << i if item_out.matches != res: self.logger.error(f"Expected {res:04b} got {item_out.matches:04b}") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class TlSequence(uvm_sequence): """ Base sequence of randomized 32-bit A and B operands along with operators picked randomly from the allowed set """ def __init__(self, name, ops=None): super().__init__(name) async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") for i in range(count): item = TlInputItem() item.randomize() await self.start_item(item) await self.finish_item(item) # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 5000) # Sequencers self.tl_seqr = uvm_sequencer("tl_seqr", self) # Driver self.tl_drv = TlDriver("tl_drv", self, dut=cocotb.top) # Monitors self.inp_mon = TlInputMonitor("inp_mon", self, dut=cocotb.top) self.out_mon = TlOutputMonitor("out_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = TlScoreboard("scoreboard", self) def connect_phase(self): self.tl_drv.seq_item_port.connect(self.tl_seqr.seq_item_export) self.inp_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.out_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/dec_tlu_ctl/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_dec_tlu_ctl_wrapper CM_FILE = cm.cfg EXTRA_ARGS = -I$(SRCDIR)/include/ VERILOG_SOURCES = \ $(SRCDIR)/dec/el2_dec_pmp_ctl.sv \ $(SRCDIR)/dec/el2_dec_tlu_ctl.sv \ $(TEST_DIR)/el2_tlu_ctl_wrapper.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/dec_tlu_ctl/cm.cfg ================================================ +tree el2_dec_tlu_ctl_wrapper.dut ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node el2_dec_tlu_ctl_wrapper.dut.dcsr[14] -node el2_dec_tlu_ctl_wrapper.dut.dcsr[9] -node el2_dec_tlu_ctl_wrapper.dut.dcsr[5:4] -node el2_dec_tlu_ctl_wrapper.dut.dcsr_ns[14] -node el2_dec_tlu_ctl_wrapper.dut.dcsr_ns[9] -node el2_dec_tlu_ctl_wrapper.dut.dcsr_ns[5:4] -node el2_dec_tlu_ctl_wrapper.dut.ifu_mscause[2] -node el2_dec_tlu_ctl_wrapper.dut.mcgc[6] -node el2_dec_tlu_ctl_wrapper.dut.mcgc_int[6] -node el2_dec_tlu_ctl_wrapper.dut.mcgc_ns[6] -node el2_dec_tlu_ctl_wrapper.dut.mcountinhibit[1] -node el2_dec_tlu_ctl_wrapper.dut.mepc_rf[0] -node el2_dec_tlu_ctl_wrapper.dut.mie_rf[31] -node el2_dec_tlu_ctl_wrapper.dut.mie_rf[27:12] -node el2_dec_tlu_ctl_wrapper.dut.mie_rf[10:8] -node el2_dec_tlu_ctl_wrapper.dut.mie_rf[6:4] -node el2_dec_tlu_ctl_wrapper.dut.mie_rf[2:0] -node el2_dec_tlu_ctl_wrapper.dut.mip_rf[27:12] -node el2_dec_tlu_ctl_wrapper.dut.mip_rf[10:8] -node el2_dec_tlu_ctl_wrapper.dut.mip_rf[6:4] -node el2_dec_tlu_ctl_wrapper.dut.mip_rf[2:0] -node el2_dec_tlu_ctl_wrapper.dut.mstatus_rf[31:17] -node el2_dec_tlu_ctl_wrapper.dut.mstatus_rf[15:12] -node el2_dec_tlu_ctl_wrapper.dut.mstatus_rf[10:8] -node el2_dec_tlu_ctl_wrapper.dut.mstatus_rf[6:4] -node el2_dec_tlu_ctl_wrapper.dut.mstatus_rf[2:0] -node el2_dec_tlu_ctl_wrapper.dut.mtdata1_tsel_out[26] -node el2_dec_tlu_ctl_wrapper.dut.mtdata1_tsel_out[18:13] -node el2_dec_tlu_ctl_wrapper.dut.mtdata1_tsel_out[10:8] -node el2_dec_tlu_ctl_wrapper.dut.mtdata1_tsel_out[5:3] -node el2_dec_tlu_ctl_wrapper.dut.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node el2_dec_tlu_ctl_wrapper.dut.pmp.*pmpcfg_ff.din[6:5] -node el2_dec_tlu_ctl_wrapper.dut.pmp.*pmpcfg_ff.dout[6:5] -node el2_dec_tlu_ctl_wrapper.dut.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node el2_dec_tlu_ctl_wrapper.dut.pmp.pmp_pmpcfg_rddata[30:29] -node el2_dec_tlu_ctl_wrapper.dut.pmp.pmp_pmpcfg_rddata[22:21] -node el2_dec_tlu_ctl_wrapper.dut.pmp.pmp_pmpcfg_rddata[14:13] -node el2_dec_tlu_ctl_wrapper.dut.pmp.pmp_pmpcfg_rddata[6:5] ================================================ FILE: verification/block/dec_tlu_ctl/common.py ================================================ from random import randrange from pyuvm import ConfigDB, uvm_sequence from testbench import PMPCheckItem class BaseSequence(uvm_sequence): MAX_ADDR = 2**32 - 4 def __init__(self, name): super().__init__(name) self.pmp_regs = ConfigDB().get(None, "", "PMP_CSRS") self.pmp_seqr = ConfigDB().get(None, "", "PMP_SEQR") self.pmp_channels = ConfigDB().get(None, "", "PMP_CHANNELS") # Access (R, W, X) memory at a given address on all channels async def accessAtAddr(self, addr): for t in range(3): type = 1 << t for c in range(self.pmp_channels): item = PMPCheckItem(channel=c, addr=addr, type=type) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) # Try to access memory at random locations in a given address range async def randomAccessInAddrRange(self, start_addr, end_addr): addr = randrange(start_addr, end_addr, 4) await self.accessAtAddr(addr) # Access memory at a given address and at adjacent addresses async def checkRangeBoundary(self, addr): # Ensure access address is always aligned and doesn't extend 32 bits, # address is assumed to be inclusive so increment it by 1 initially. addr = min(self.MAX_ADDR, (addr + 1) & 0xFFFFFFFC) if addr >= 4: await self.accessAtAddr(addr - 4) await self.accessAtAddr(addr) if addr < self.MAX_ADDR: await self.accessAtAddr(addr + 4) ================================================ FILE: verification/block/dec_tlu_ctl/el2_tlu_ctl_wrapper.sv ================================================ module el2_dec_tlu_ctl_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic free_clk, input logic free_l2clk, input logic rst_l, // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core. /*pragma coverage off*/ input logic scan_mode, /*pragma coverage on*/ //rst_vec is supposed to be connected to constant in the top level /*pragma coverage off*/ input logic [31:1] rst_vec, // reset vector, from core pins /*pragma coverage on*/ input logic nmi_int, // nmi pin //nmi_vec is supposed to be connected to constant in the top level /*pragma coverage off*/ input logic [31:1] nmi_vec, // nmi vector /*pragma coverage on*/ input logic i_cpu_halt_req, // Asynchronous Halt request to CPU input logic i_cpu_run_req, // Asynchronous Restart request to CPU input logic lsu_fastint_stall_any, // needed by lsu for 2nd pass of dma with ecc correction, stall next cycle // perf counter inputs input logic ifu_pmu_instr_aligned, // aligned instructions input logic ifu_pmu_fetch_stall, // fetch unit stalled input logic ifu_pmu_ic_miss, // icache miss input logic ifu_pmu_ic_hit, // icache hit input logic ifu_pmu_bus_error, // Instruction side bus error input logic ifu_pmu_bus_busy, // Instruction side bus busy input logic ifu_pmu_bus_trxn, // Instruction side bus transaction input logic dec_pmu_instr_decoded, // decoded instructions input logic dec_pmu_decode_stall, // decode stall input logic dec_pmu_presync_stall, // decode stall due to presync'd inst input logic dec_pmu_postsync_stall,// decode stall due to postsync'd inst input logic lsu_store_stall_any, // SB or WB is full, stall decode input logic dma_dccm_stall_any, // DMA stall of lsu input logic dma_iccm_stall_any, // DMA stall of ifu input logic exu_pmu_i0_br_misp, // pipe 0 branch misp input logic exu_pmu_i0_br_ataken, // pipe 0 branch actual taken input logic exu_pmu_i0_pc4, // pipe 0 4 byte branch input logic lsu_pmu_bus_trxn, // D side bus transaction input logic lsu_pmu_bus_misaligned, // D side bus misaligned input logic lsu_pmu_bus_error, // D side bus error input logic lsu_pmu_bus_busy, // D side bus busy input logic lsu_pmu_load_external_m, // D side bus load input logic lsu_pmu_store_external_m, // D side bus store input logic dma_pmu_dccm_read, // DMA DCCM read input logic dma_pmu_dccm_write, // DMA DCCM write input logic dma_pmu_any_read, // DMA read input logic dma_pmu_any_write, // DMA write input logic [31:1] lsu_fir_addr, // Fast int address input logic [1:0] lsu_fir_error, // Fast int lookup error input logic iccm_dma_sb_error, // I side dma single bit error input logic lsu_single_ecc_error_incr, // LSU inc SB error counter input logic dec_pause_state, // Pause counter not zero input logic lsu_imprecise_error_store_any, // store bus error input logic lsu_imprecise_error_load_any, // store bus error input logic [31:0] lsu_imprecise_error_addr_any, // store bus error address input logic dec_csr_wen_unq_d, // valid csr with write - for csr legal input logic dec_csr_any_unq_d, // valid csr - for csr legal input logic [11:0] dec_csr_rdaddr_d, // read address for csr input logic dec_csr_wen_r, // csr write enable at wb input logic [11:0] dec_csr_rdaddr_r, // read address for csr input logic [11:0] dec_csr_wraddr_r, // write address for csr input logic [31:0] dec_csr_wrdata_r, // csr write data at wb input logic dec_csr_stall_int_ff, // csr is mie/mstatus input logic dec_tlu_i0_valid_r, // pipe 0 op at e4 is valid input logic [31:1] exu_npc_r, // for NPC tracking input logic [31:1] dec_tlu_i0_pc_r, // for PC/NPC tracking input logic [31:0] dec_illegal_inst, // For mtval input logic dec_i0_decode_d, // decode valid, used for clean icache diagnostics // branch info from pipe0 for errors or counter updates input logic [1:0] exu_i0_br_hist_r, // history input logic exu_i0_br_error_r, // error input logic exu_i0_br_start_error_r, // start error input logic exu_i0_br_valid_r, // valid input logic exu_i0_br_mp_r, // mispredict input logic exu_i0_br_middle_r, // middle of bank // branch info from pipe1 for errors or counter updates input logic exu_i0_br_way_r, // way hit or repl output logic dec_tlu_core_empty, // core is empty // Debug start output logic dec_dbg_cmd_done, // abstract command done output logic dec_dbg_cmd_fail, // abstract command failed output logic dec_tlu_dbg_halted, // Core is halted and ready for debug command output logic dec_tlu_debug_mode, // Core is in debug mode output logic dec_tlu_resume_ack, // Resume acknowledge output logic dec_tlu_debug_stall, // stall decode while waiting on core to empty output logic dec_tlu_flush_noredir_r , // Tell fetch to idle on this flush output logic dec_tlu_mpc_halted_only, // Core is halted only due to MPC output logic dec_tlu_flush_leak_one_r, // single step output logic dec_tlu_flush_err_r, // iside perr/ecc rfpc. This is the D stage of the error output logic dec_tlu_flush_extint, // fast ext int started output logic [31:2] dec_tlu_meihap, // meihap for fast int input logic dbg_halt_req, // DM requests a halt input logic dbg_resume_req, // DM requests a resume input logic ifu_miss_state_idle, // I-side miss buffer empty input logic lsu_idle_any, // lsu is idle input logic dec_div_active, // oop div is active // el2_trigger_pkt_t broken down to allow driving from cocotb by both SIMs // info needed by debug trigger blocks output logic [3:0] trigger_pkt_any_select, output logic [3:0] trigger_pkt_any_match, output logic [3:0] trigger_pkt_any_store, output logic [3:0] trigger_pkt_any_load, output logic [3:0] trigger_pkt_any_execute, output logic [3:0] trigger_pkt_any_m, output logic [3:0][31:0] trigger_pkt_any_tdata2, input logic ifu_ic_error_start, // IC single bit error input logic ifu_iccm_rd_ecc_single_err, // ICCM single bit error input logic [70:0] ifu_ic_debug_rd_data, // diagnostic icache read data input logic ifu_ic_debug_rd_data_valid, // diagnostic icache read data valid output el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt, // packet of DICAWICS, DICAD0/1, DICAGO info for icache diagnostics // Debug end input logic [7:0] pic_claimid, // pic claimid for csr input logic [3:0] pic_pl, // pic priv level for csr input logic mhwakeup, // high priority external int, wakeup if halted input logic mexintpend, // external interrupt pending input logic timer_int, // timer interrupt pending input logic soft_int, // software interrupt pending output logic o_cpu_halt_status, // PMU interface, halted output logic o_cpu_halt_ack, // halt req ack output logic o_cpu_run_ack, // run req ack output logic o_debug_mode_status, // Core to the PMU that core is in debug mode. When core is in debug mode, the PMU should refrain from sendng a halt or run request /*pragma coverage off*/ input logic [31:4] core_id, // Core ID /*pragma coverage on*/ // external MPC halt/run interface input logic mpc_debug_halt_req, // Async halt request input logic mpc_debug_run_req, // Async run request input logic mpc_reset_run_req, // Run/halt after reset output logic mpc_debug_halt_ack, // Halt ack output logic mpc_debug_run_ack, // Run ack output logic debug_brkpt_status, // debug breakpoint output logic [3:0] dec_tlu_meicurpl, // to PIC output logic [3:0] dec_tlu_meipt, // to PIC output logic [31:0] dec_csr_rddata_d, // csr read data at wb output logic dec_csr_legal_d, // csr indicates legal operation output el2_br_tlu_pkt_t dec_tlu_br0_r_pkt, // branch pkt to bp output logic dec_tlu_i0_kill_writeb_wb, // I0 is flushed, don't writeback any results to arch state output logic dec_tlu_flush_lower_wb, // commit has a flush (exception, int, mispredict at e4) output logic dec_tlu_i0_commit_cmt, // committed an instruction output logic dec_tlu_i0_kill_writeb_r, // I0 is flushed, don't writeback any results to arch state output logic dec_tlu_flush_lower_r, // commit has a flush (exception, int) output logic [31:1] dec_tlu_flush_path_r, // flush pc output logic dec_tlu_fence_i_r, // flush is a fence_i rfnpc, flush icache output logic dec_tlu_wr_pause_r, // CSR write to pause reg is at R. output logic dec_tlu_flush_pause_r, // Flush is due to pause output logic dec_tlu_presync_d, // CSR read needs to be presync'd output logic dec_tlu_postsync_d, // CSR needs to be presync'd output logic [31:0] dec_tlu_mrac_ff, // CSR for memory region control output logic dec_tlu_force_halt, // halt has been forced output logic dec_tlu_perfcnt0, // toggles when pipe0 perf counter 0 has an event inc output logic dec_tlu_perfcnt1, // toggles when pipe0 perf counter 1 has an event inc output logic dec_tlu_perfcnt2, // toggles when pipe0 perf counter 2 has an event inc output logic dec_tlu_perfcnt3, // toggles when pipe0 perf counter 3 has an event inc output logic dec_tlu_i0_exc_valid_wb1, // pipe 0 exception valid output logic dec_tlu_i0_valid_wb1, // pipe 0 valid output logic dec_tlu_int_valid_wb1, // pipe 2 int valid output logic [4:0] dec_tlu_exc_cause_wb1, // exception or int cause output logic [31:0] dec_tlu_mtval_wb1, // MTVAL value // feature disable from mfdc output logic dec_tlu_external_ldfwd_disable, // disable external load forwarding output logic dec_tlu_sideeffect_posted_disable, // disable posted stores to side-effect address output logic dec_tlu_core_ecc_disable, // disable core ECC output logic dec_tlu_bpred_disable, // disable branch prediction output logic dec_tlu_wb_coalescing_disable, // disable writebuffer coalescing output logic dec_tlu_pipelining_disable, // disable pipelining output logic dec_tlu_trace_disable, // disable trace output logic [2:0] dec_tlu_dma_qos_prty, // DMA QoS priority coming from MFDC [18:16] // clock gating overrides from mcgc output logic dec_tlu_misc_clk_override, // override misc clock domain gating output logic dec_tlu_dec_clk_override, // override decode clock domain gating output logic dec_tlu_ifu_clk_override, // override fetch clock domain gating output logic dec_tlu_lsu_clk_override, // override load/store clock domain gating output logic dec_tlu_bus_clk_override, // override bus clock domain gating output logic dec_tlu_pic_clk_override, // override PIC clock domain gating output logic dec_tlu_picio_clk_override,// override PICIO clock domain gating output logic dec_tlu_dccm_clk_override, // override DCCM clock domain gating output logic dec_tlu_icm_clk_override, // override ICCM clock domain gating `ifdef RV_USER_MODE // Privilege mode // 0 - machine, 1 - user output logic priv_mode, output logic priv_mode_eff, output logic priv_mode_ns, // mseccfg CSR content for PMP output logic [2:0] mseccfg, `endif // pmp output el2_pmp_cfg_pkt_t pmp_pmpcfg [pt.PMP_ENTRIES], output logic [31:0] pmp_pmpaddr [pt.PMP_ENTRIES] ); el2_lsu_error_pkt_t lsu_error_pkt_r; el2_trap_pkt_t dec_tlu_packet_r; el2_trigger_pkt_t [3:0] trigger_pkt_any; // Unwrap structure support both simulators for (genvar i = 0; i < 4; i++) begin : g_unwrap_el2_trigger_pkt_t assign trigger_pkt_any_select[i] = trigger_pkt_any[i][37]; assign trigger_pkt_any_match[i] = trigger_pkt_any[i][36]; assign trigger_pkt_any_store[i] = trigger_pkt_any[i][35]; assign trigger_pkt_any_load[i] = trigger_pkt_any[i][34]; assign trigger_pkt_any_execute[i] = trigger_pkt_any[i][33]; assign trigger_pkt_any_m[i] = trigger_pkt_any[i][32]; assign trigger_pkt_any_tdata2[i] = trigger_pkt_any[i][31:0]; end assign lsu_error_pkt_r = '0; assign dec_tlu_packet_r = '0; el2_dec_tlu_ctl dut ( .lsu_error_pkt_r(lsu_error_pkt_r), .dec_tlu_packet_r(dec_tlu_packet_r), .* ); endmodule ================================================ FILE: verification/block/dec_tlu_ctl/test_dec_tl.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseTest, TlSequence # ============================================================================= @pyuvm.test() class TestMeihap(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() ConfigDB().set(None, "*", "TEST", "meihap") self.seq = TlSequence("stimulus") async def run(self): await self.seq.start(self.env.tl_seqr) @pyuvm.test() class TestMtdata(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() ConfigDB().set(None, "*", "TEST", "mtdata") self.seq = TlSequence("stimulus") async def run(self): await self.seq.start(self.env.tl_seqr) @pyuvm.test() class TestMhpme(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() ConfigDB().set(None, "*", "TEST", "mhpme") self.seq = TlSequence("stimulus") async def run(self): await self.seq.start(self.env.tl_seqr) @pyuvm.test() class TestMdseac(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() ConfigDB().set(None, "*", "TEST", "mdseac") self.seq = TlSequence("stimulus") async def run(self): await self.seq.start(self.env.tl_seqr) @pyuvm.test() class TestCsrAccess(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() ConfigDB().set(None, "*", "TEST", "csrs_access") self.seq = TlSequence("stimulus") async def run(self): await self.seq.start(self.env.tl_seqr) @pyuvm.test() class TestDebugCSRs(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() ConfigDB().set(None, "*", "TEST", "debug_csrs_access") self.seq = TlSequence("stimulus") async def run(self): await self.seq.start(self.env.tl_seqr) @pyuvm.test() class TestDebugICCache(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() ConfigDB().set(None, "*", "TEST", "debug_ic_cache") self.seq = TlSequence("stimulus") async def run(self): await self.seq.start(self.env.tl_seqr) ================================================ FILE: verification/block/dec_tlu_ctl/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import copy import math import os import random import struct from dataclasses import dataclass import csrs import pyuvm from cocotb.binary import BinaryValue from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from cocotb.types import Array, Range from pyuvm import * # ============================================================================== csr_list = [getattr(csrs, mod) for mod in dir(csrs) if isinstance(getattr(csrs, mod), csrs.CSR)] @dataclass class TriggerAnyPktT: select: int = 0 match: int = 0 store: int = 0 load: int = 0 execute: int = 0 m: int = 0 tdata2: int = 0 @staticmethod def get_from_dut(dut): trigger_pkt_any_select = int(dut.trigger_pkt_any_select.value) trigger_pkt_any_match = int(dut.trigger_pkt_any_match.value) trigger_pkt_any_store = int(dut.trigger_pkt_any_store.value) trigger_pkt_any_load = int(dut.trigger_pkt_any_load.value) trigger_pkt_any_execute = int(dut.trigger_pkt_any_execute.value) trigger_pkt_any_m = int(dut.trigger_pkt_any_m.value) trigger_pkt_any_tdata2 = int(dut.trigger_pkt_any_tdata2.value) return TriggerAnyPktT( trigger_pkt_any_select, trigger_pkt_any_match, trigger_pkt_any_store, trigger_pkt_any_load, trigger_pkt_any_execute, trigger_pkt_any_m, trigger_pkt_any_tdata2, ) class TlInputItem(uvm_sequence_item): """ Trigger Logic output data """ def __init__( self, pic_claimid=0, dec_csr_wrdata_r=0, mtdata1=0, mtdata2=0, mtsel=0, mdeau=0, csr_addr=0, dec_csr_rddata_d=0, ifu_ic_debug_rd_data=0, lsu_imprecise_error_addr_any=0, ): super().__init__("TlOutputItem") self.pic_claimid = pic_claimid self.dec_csr_wrdata_r = dec_csr_wrdata_r self.mtdata1 = mtdata1 self.mtdata2 = mtdata2 self.mtsel = mtsel self.csr_addr = csr_addr self.mtsel = mtsel self.mdeau = mdeau self.dec_csr_rddata_d = dec_csr_rddata_d self.ifu_ic_debug_rd_data = ifu_ic_debug_rd_data self.lsu_imprecise_error_addr_any = lsu_imprecise_error_addr_any def randomize(self, test): if test == "meihap": pic_claimid = "" # CSR dec_csr_wrdata_r = "" for _ in range(8): pic_claimid += random.choice(["0", "1"]) for _ in range(22): dec_csr_wrdata_r += random.choice(["0", "1"]) self.pic_claimid = int(pic_claimid, 2) self.dec_csr_wrdata_r = int(dec_csr_wrdata_r, 2) << 10 elif test == "mhpme": value = "" for _ in range(10): value += random.choice(["0", "1"]) self.dec_csr_wrdata_r = int(value, 2) self.csr_addr = random.choice( [ csrs.MHPME3, csrs.MHPME4, csrs.MHPME5, csrs.MHPME6, ] ) elif test == "mtdata": # bits 31:28 are hardcoded to 0x2 mtdata1 = "0010" mtdata2 = "" mtsel = "" for _ in range(28): mtdata1 += random.choice(["0", "1"]) # set DMODE (bit 27) to 0 so that the settigs are actually taken into account # in the list, bits are nubered from 0 tmp = list(mtdata1) tmp[31 - 27] = "0" mtdata1 = "".join(tmp) self.mtdata1 = int(mtdata1, 2) for _ in range(32): mtdata2 += random.choice(["0", "1"]) self.mtdata2 = int(mtdata2, 2) for _ in range(2): mtsel += random.choice(["0", "1"]) self.mtsel = int(mtsel, 2) elif test == "mdseac": mdeau = "" for _ in range(32): mdeau += random.choice(["0", "1"]) self.mdeau = int(mdeau, 2) value = "" for _ in range(32): value += random.choice(["0", "1"]) self.lsu_imprecise_error_addr_any = int(value, 2) self.csr_addr = csrs.MDSEAC elif test == "csrs_access": value = "" for _ in range(32): value += random.choice(["0", "1"]) self.dec_csr_wrdata_r = int(value, 2) self.csr_addr = random.choice( [ csrs.MHPMC3, csrs.MHPMC3H, csrs.MHPMC4, csrs.MHPMC4H, csrs.MHPMC5, csrs.MHPMC5H, csrs.MHPMC6, csrs.MHPMC6H, csrs.MCYCLEL, csrs.MCYCLEH, csrs.MINSTRETL, csrs.MINSTRETH, csrs.MICECT, csrs.MICCMECT, csrs.MDCCMECT, csrs.MTVEC, csrs.MHPME3, csrs.MHPME4, csrs.MHPME5, csrs.MHPME6, csrs.MRAC, csrs.MEIPT, csrs.MCOUNTINHIBIT, csrs.MFDHT, csrs.MEICURPL, csrs.MFDC, ] ) elif test == "debug_csrs_access": value = "" for _ in range(32): value += random.choice(["0", "1"]) self.dec_csr_wrdata_r = int(value, 2) self.csr_addr = random.choice( [csrs.DICAD0, csrs.DICAD0H, csrs.DICAWICS, csrs.DPC, csrs.DCSR] ) elif test == "debug_ic_cache": value = "" for _ in range(71): value += random.choice(["0", "1"]) self.ifu_ic_debug_rd_data = int(value, 2) class TlOutputItem(uvm_sequence_item): """ Trigger Logic output data """ def __init__( self, dec_tlu_meihap=0, mtdata1=0, mtdata2=0, mtsel=0, trigger_pkt_any=0, dec_csr_rddata_d=0, ifu_ic_debug_rd_data=0, ): super().__init__("TlOutputItem") self.dec_tlu_meihap = dec_tlu_meihap self.mtdata1 = mtdata1 self.mtdata2 = mtdata2 self.mtsel = mtsel self.trigger_pkt_any = trigger_pkt_any self.dec_csr_rddata_d = dec_csr_rddata_d self.ifu_ic_debug_rd_data = ifu_ic_debug_rd_data # ============================================================================== class TlDriver(uvm_driver): """ Trigger Logic driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def read_csr(self, address): self.dut.dec_csr_rdaddr_d.value = address await RisingEdge(self.dut.clk) async def write_csr(self, address, value): self.dut.dec_csr_wen_r.value = 0 await RisingEdge(self.dut.clk) self.dut.dec_csr_wen_r.value = 1 self.dut.dec_csr_wraddr_r.value = address self.dut.dec_csr_wrdata_r.value = value await RisingEdge(self.dut.clk) self.dut.dec_csr_wen_r.value = 0 async def do_reset(self): self.dut.rst_l.value = 0 await ClockCycles(self.dut.clk, 2) await FallingEdge(self.dut.clk) self.dut.rst_l.value = 1 async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, TlInputItem): test = ConfigDB().get(self, "", "TEST") if test == "meihap": # write MEIVT await self.write_csr(csrs.MEIVT, it.dec_csr_wrdata_r) # write pic_claimid await RisingEdge(self.dut.clk) self.dut.pic_claimid.value = it.pic_claimid self.dut.dec_csr_wen_r.value = 1 self.dut.dec_csr_wraddr_r.value = csrs.MEICPCT await RisingEdge(self.dut.clk) self.dut.dec_csr_wen_r.value = 0 # give two more cycles so that output monitor can catch the data on the outputs await RisingEdge(self.dut.clk) await RisingEdge(self.dut.clk) elif test == "mtdata": # test triggers await self.write_csr(csrs.MTSEL, it.mtsel) await self.write_csr(csrs.MTDATA1, it.mtdata1) await self.write_csr(csrs.MTDATA2, it.mtdata2) elif test == "mdseac": # Write to unlock register await self.write_csr(csrs.MDEAU, it.mdeau) if self.dut.dut.mdseac_locked_f.value: await FallingEdge(self.dut.mdseac_locked_f) await RisingEdge(self.dut.clk) # Write error self.dut.lsu_imprecise_error_addr_any.value = it.lsu_imprecise_error_addr_any self.dut.lsu_imprecise_error_store_any.value = 1 await RisingEdge(self.dut.clk) self.dut.lsu_imprecise_error_store_any.value = 0 await RisingEdge(self.dut.clk) # Read the MDSEAC register await self.read_csr(it.csr_addr) # Perform reset to clear the error await self.do_reset() elif test in ["csrs_access", "mhpme"]: # write a perf counter await self.write_csr(it.csr_addr, it.dec_csr_wrdata_r) # read it back await self.read_csr(it.csr_addr) elif test == "debug_csrs_access": # request halt self.dut.dbg_halt_req.value = 1 for _ in range(2): await RisingEdge(self.dut.clk) # write a perf counter await self.write_csr(it.csr_addr, it.dec_csr_wrdata_r) # read it back await self.read_csr(it.csr_addr) elif test == "debug_ic_cache": self.dut.ifu_ic_debug_rd_data_valid.value = 1 self.dut.ifu_ic_debug_rd_data.value = it.ifu_ic_debug_rd_data await RisingEdge(self.dut.clk) self.dut.ifu_ic_debug_rd_data_valid.value = 0 self.dut.ifu_ic_debug_rd_data.value = 0 await self.read_csr(csrs.DICAD0) await self.read_csr(csrs.DICAD0H) await self.read_csr(csrs.DICAD1) else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class TlInputMonitor(uvm_component): """ Monitor for Trigger Logic inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: test = ConfigDB().get(self, "", "TEST") if test == "meihap": # Wait for the driver to set the input signals await RisingEdge(self.dut.dec_csr_wen_r) await RisingEdge(self.dut.dec_csr_wen_r) # for _ in range(4): # await RisingEdge(self.dut.clk) pic_claimid = int(self.dut.pic_claimid.value) meivt = int(self.dut.dec_csr_wrdata_r.value) self.ap.write(TlInputItem(pic_claimid=pic_claimid, dec_csr_wrdata_r=meivt)) elif test == "mtdata": await RisingEdge(self.dut.dec_csr_wen_r) await RisingEdge(self.dut.clk) mtsel = int(self.dut.dec_csr_wrdata_r.value) await RisingEdge(self.dut.dec_csr_wen_r) await RisingEdge(self.dut.clk) mtdata1 = int(self.dut.dec_csr_wrdata_r.value) await RisingEdge(self.dut.dec_csr_wen_r) await RisingEdge(self.dut.clk) mtdata2 = int(self.dut.dec_csr_wrdata_r.value) self.ap.write(TlInputItem(mtdata1=mtdata1, mtdata2=mtdata2, mtsel=mtsel)) elif test == "mdseac": await RisingEdge(self.dut.lsu_imprecise_error_store_any) await RisingEdge(self.dut.clk) csr_addr = int(self.dut.dec_csr_rdaddr_d.value) lsu_imprecise_error_addr_any = int(self.dut.lsu_imprecise_error_addr_any.value) self.ap.write( TlInputItem( csr_addr=csr_addr, lsu_imprecise_error_addr_any=lsu_imprecise_error_addr_any ) ) elif test in ["csrs_access", "mhpme"]: # wait for reg write await RisingEdge(self.dut.dec_csr_wen_r) await RisingEdge(self.dut.clk) csr_addr = int(self.dut.dec_csr_wraddr_r.value) csr_value = int(self.dut.dec_csr_wrdata_r.value) self.ap.write(TlInputItem(csr_addr=csr_addr, dec_csr_wrdata_r=csr_value)) elif test == "debug_csrs_access": # wait for debug mode for _ in range(2): await RisingEdge(self.dut.clk) # wait for reg write await RisingEdge(self.dut.dec_csr_wen_r) await RisingEdge(self.dut.clk) csr_addr = int(self.dut.dec_csr_wraddr_r.value) csr_value = int(self.dut.dec_csr_wrdata_r.value) self.ap.write(TlInputItem(csr_addr=csr_addr, dec_csr_wrdata_r=csr_value)) elif test == "debug_ic_cache": # wait for reg write await RisingEdge(self.dut.ifu_ic_debug_rd_data_valid) await RisingEdge(self.dut.clk) ic_debug_rd_data = int(self.dut.ifu_ic_debug_rd_data.value) self.ap.write(TlInputItem(ifu_ic_debug_rd_data=ic_debug_rd_data)) class TlOutputMonitor(uvm_component): """ Monitor for Trigger Logic outputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: test = ConfigDB().get(self, "", "TEST") if test == "meihap": # Wait for the driver to set the input signals and the data goes through await RisingEdge(self.dut.dec_csr_wen_r) await RisingEdge(self.dut.dec_csr_wen_r) for _ in range(2): await RisingEdge(self.dut.clk) dec_tlu_meihap = int(self.dut.dec_tlu_meihap.value) << 2 self.ap.write(TlOutputItem(dec_tlu_meihap)) elif test == "mtdata": # wait for reg writes for _ in range(3): await RisingEdge(self.dut.dec_csr_wen_r) # wait for the outputs for _ in range(2): await RisingEdge(self.dut.clk) trigger_pkt_any = TriggerAnyPktT.get_from_dut(self.dut) self.ap.write(TlOutputItem(trigger_pkt_any=trigger_pkt_any)) elif test == "mdseac": # Wait for when the error address is set await RisingEdge(self.dut.lsu_imprecise_error_store_any) # Wait for read for _ in range(3): await RisingEdge(self.dut.clk) dec_csr_rddata_d = int(self.dut.dec_csr_rddata_d.value) self.ap.write(TlOutputItem(dec_csr_rddata_d=dec_csr_rddata_d)) elif test in ["csrs_access", "mhpme"]: # wait for reg write await RisingEdge(self.dut.dec_csr_wen_r) # wait for read for _ in range(2): await RisingEdge(self.dut.clk) dec_csr_rddata_d = int(self.dut.dec_csr_rddata_d.value) self.ap.write(TlOutputItem(dec_csr_rddata_d=dec_csr_rddata_d)) elif test == "debug_csrs_access": # wait for debug mode for _ in range(2): await RisingEdge(self.dut.clk) # wait for reg write await RisingEdge(self.dut.dec_csr_wen_r) # wait for read for _ in range(2): await RisingEdge(self.dut.clk) dec_csr_rddata_d = int(self.dut.dec_csr_rddata_d.value) self.ap.write(TlOutputItem(dec_csr_rddata_d=dec_csr_rddata_d)) elif test == "debug_ic_cache": # wait for read # read dicad0, dicad0h, and dicad1 await RisingEdge(self.dut.ifu_ic_debug_rd_data_valid) for _ in range(2): await RisingEdge(self.dut.clk) dicad0 = int(self.dut.dec_csr_rddata_d.value) await RisingEdge(self.dut.clk) dicad0h = int(self.dut.dec_csr_rddata_d.value) await RisingEdge(self.dut.clk) dicad1 = int(self.dut.dec_csr_rddata_d.value) ifu_ic_debug_rd_data = dicad0 | (dicad0h << 32) | (dicad1 << 64) self.ap.write(TlOutputItem(ifu_ic_debug_rd_data=ifu_ic_debug_rd_data)) # ============================================================================== class TlScoreboard(uvm_component): """ Trigger Logic scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): # noqa: C901 # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True test = ConfigDB().get(self, "", "TEST") if test == "meihap": sent_pic_claimid = item_inp.pic_claimid sent_meivt = item_inp.dec_csr_wrdata_r >> 12 recv_pic_claimid = (item_out.dec_tlu_meihap >> 2) & 0xFF recv_meivt = item_out.dec_tlu_meihap >> 12 if sent_pic_claimid != recv_pic_claimid: self.logger.error( "pic_claimid {} != {} (should be {})".format( sent_pic_claimid, recv_pic_claimid, sent_pic_claimid ) ) self.passed = False if sent_meivt != recv_meivt: self.logger.error( "meivt {} != {} (should be {})".format(sent_meivt, recv_meivt, sent_meivt) ) self.passed = False elif test == "mtdata": tdata2_mask = 0xFFFFFFFF mtsel = item_inp.mtsel mtdata1_i = item_inp.mtdata1 mtdata2_i = item_inp.mtdata2 trigger_pkt_any = item_out.trigger_pkt_any select_i = (mtdata1_i >> 19) & 1 match_i = (mtdata1_i >> 7) & 1 store_i = (mtdata1_i >> 1) & 1 load_i = ((mtdata1_i >> 0) & 1) & ~((mtdata1_i >> 19) & 1) execute_i = ((mtdata1_i >> 2) & 1) & ~((mtdata1_i >> 19) & 1) m_i = (mtdata1_i >> 6) & 1 select_o = (trigger_pkt_any.select >> mtsel) & 1 match_o = (trigger_pkt_any.match >> mtsel) & 1 store_o = (trigger_pkt_any.store >> mtsel) & 1 load_o = (trigger_pkt_any.load >> mtsel) & 1 execute_o = (trigger_pkt_any.execute >> mtsel) & 1 m_o = (trigger_pkt_any.m >> mtsel) & 1 mtdata2_o = (trigger_pkt_any.tdata2 >> (mtsel * 32)) & tdata2_mask if mtdata2_i != mtdata2_o: self.logger.error( "mtdata2 {} != {} (should be {})".format(mtdata2_i, mtdata2_o, mtdata2_i) ) self.passed = False if select_i != select_o: self.logger.error( "select {} != {} (should be {})".format(select_i, select_o, select_i) ) self.passed = False if match_i != match_o: self.logger.error( "match {} != {} (should be {})".format(match_i, match_o, match_i) ) self.passed = False if store_i != store_o: self.logger.error( "store {} != {} (should be {})".format(store_i, store_o, store_i) ) self.passed = False if load_i != load_o: self.logger.error("load {} != {} (should be {})".format(load_i, load_o, load_i)) self.passed = False if execute_i != execute_o: self.logger.error( "execute {} != {} (should be {})".format(execute_i, execute_o, execute_i) ) self.passed = False if m_i != m_o: self.logger.error("m {} != {} (should be {})".format(m_i, m_o, m_i)) self.passed = False elif test == "mhpme": csr = item_inp.csr_addr perf_reg_val_i = item_inp.dec_csr_wrdata_r perf_reg_val_o = item_out.dec_csr_rddata_d mhpme_lst = [csrs.MHPME3, csrs.MHPME4, csrs.MHPME5, csrs.MHPME6] c = [c for c in mhpme_lst if c == csr][0] perf_reg_val_i = c.out(perf_reg_val_i) if perf_reg_val_i != perf_reg_val_o: self.logger.error( "reg_val[{}] {} != {} (should be {})".format( hex(csr), hex(perf_reg_val_i), hex(perf_reg_val_o), hex(perf_reg_val_i) ) ) self.passed = False elif test == "mdseac": csr = item_inp.csr_addr error_val_i = item_inp.lsu_imprecise_error_addr_any mdseac_val_o = item_out.dec_csr_rddata_d if error_val_i != mdseac_val_o: self.logger.error( "reg_val[{}] {} != {} (should be {})".format( hex(csr), hex(error_val_i), hex(mdseac_val_o), hex(error_val_i) ) ) self.passed = False elif test == "csrs_access": csr = item_inp.csr_addr perf_reg_val_i = item_inp.dec_csr_wrdata_r perf_reg_val_o = item_out.dec_csr_rddata_d for c in csr_list: if c == csr: perf_reg_val_i = c.out(perf_reg_val_i) break if perf_reg_val_i != perf_reg_val_o: self.logger.error( "reg_val[{}] {} != {} (should be {})".format( hex(csr), hex(perf_reg_val_i), hex(perf_reg_val_o), hex(perf_reg_val_i) ) ) self.passed = False elif test == "debug_csrs_access": csr = item_inp.csr_addr reg_val_i = item_inp.dec_csr_wrdata_r reg_val_o = item_out.dec_csr_rddata_d if csr == csrs.DCSR: reg_val_i = csrs.DCSR.out(reg_val_i) elif csr == csrs.DPC: reg_val_i = csrs.DPC.out(reg_val_i) elif csr == csrs.DICAWICS: reg_val_i = csrs.DICAWICS.out(reg_val_i) if reg_val_i != reg_val_o: self.logger.error( "reg_val[{}] {} != {} (should be {})".format( hex(csr), hex(reg_val_i), hex(reg_val_o), hex(reg_val_i) ) ) self.passed = False elif test == "debug_ic_cache": ifu_ic_debug_rd_data_in = item_inp.ifu_ic_debug_rd_data ifu_ic_debug_rd_data_out = item_out.ifu_ic_debug_rd_data if ifu_ic_debug_rd_data_in != ifu_ic_debug_rd_data_out: self.logger.error( "read_data {} != {} (should be {})".format( hex(ifu_ic_debug_rd_data_in), hex(ifu_ic_debug_rd_data_out), hex(ifu_ic_debug_rd_data_in), ) ) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class TlSequence(uvm_sequence): def __init__(self, name, ops=None): super().__init__(name) async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") test = ConfigDB().get(None, "", "TEST") for i in range(count): item = TlInputItem() item.randomize(test) await self.start_item(item) await self.finish_item(item) # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 5000) # Sequencers self.tl_seqr = uvm_sequencer("tl_seqr", self) # Driver self.tl_drv = TlDriver("tl_drv", self, dut=cocotb.top) # Monitors self.inp_mon = TlInputMonitor("inp_mon", self, dut=cocotb.top) self.out_mon = TlOutputMonitor("out_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = TlScoreboard("scoreboard", self) def connect_phase(self): self.tl_drv.seq_item_port.connect(self.tl_seqr.seq_item_export) self.inp_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.out_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Ba5e test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() cocotb.top.rst_vec.value = 0 cocotb.top.nmi_int.value = 0 cocotb.top.nmi_vec.value = 0 cocotb.top.i_cpu_halt_req.value = 0 cocotb.top.i_cpu_run_req.value = 0 cocotb.top.lsu_fastint_stall_any.value = 0 cocotb.top.ifu_pmu_instr_aligned.value = 0 cocotb.top.ifu_pmu_fetch_stall.value = 0 cocotb.top.ifu_pmu_ic_miss.value = 0 cocotb.top.ifu_pmu_ic_hit.value = 0 cocotb.top.ifu_pmu_bus_error.value = 0 cocotb.top.ifu_pmu_bus_busy.value = 0 cocotb.top.ifu_pmu_bus_trxn.value = 0 cocotb.top.dec_pmu_instr_decoded.value = 0 cocotb.top.dec_pmu_decode_stall.value = 0 cocotb.top.dec_pmu_presync_stall.value = 0 cocotb.top.dec_pmu_postsync_stall.value = 0 cocotb.top.lsu_store_stall_any.value = 0 cocotb.top.dma_dccm_stall_any.value = 0 cocotb.top.dma_iccm_stall_any.value = 0 cocotb.top.exu_pmu_i0_br_misp.value = 0 cocotb.top.exu_pmu_i0_br_ataken.value = 0 cocotb.top.exu_pmu_i0_pc4.value = 0 cocotb.top.lsu_pmu_bus_trxn.value = 0 cocotb.top.lsu_pmu_bus_misaligned.value = 0 cocotb.top.lsu_pmu_bus_error.value = 0 cocotb.top.lsu_pmu_bus_busy.value = 0 cocotb.top.lsu_pmu_load_external_m.value = 0 cocotb.top.lsu_pmu_store_external_m.value = 0 cocotb.top.dma_pmu_dccm_read.value = 0 cocotb.top.dma_pmu_dccm_write.value = 0 cocotb.top.dma_pmu_any_read.value = 0 cocotb.top.dma_pmu_any_write.value = 0 cocotb.top.lsu_fir_addr.value = 0 cocotb.top.lsu_fir_error.value = 0 cocotb.top.iccm_dma_sb_error.value = 0 cocotb.top.lsu_single_ecc_error_incr.value = 0 cocotb.top.dec_pause_state.value = 0 cocotb.top.lsu_imprecise_error_store_any.value = 0 cocotb.top.lsu_imprecise_error_load_any.value = 0 cocotb.top.lsu_imprecise_error_addr_any.value = 0 cocotb.top.dec_csr_wen_unq_d.value = 0 cocotb.top.dec_csr_any_unq_d.value = 0 cocotb.top.dec_csr_rdaddr_d.value = 0 cocotb.top.dec_csr_wen_r.value = 0 cocotb.top.dec_csr_rdaddr_r.value = 0 cocotb.top.dec_csr_wraddr_r.value = 0 cocotb.top.dec_csr_wrdata_r.value = 0 cocotb.top.dec_csr_stall_int_ff.value = 0 cocotb.top.dec_tlu_i0_valid_r.value = 0 cocotb.top.exu_npc_r.value = 0 cocotb.top.dec_tlu_i0_pc_r.value = 0 cocotb.top.dec_illegal_inst.value = 0 cocotb.top.dec_i0_decode_d.value = 0 cocotb.top.exu_i0_br_hist_r.value = 0 cocotb.top.exu_i0_br_error_r.value = 0 cocotb.top.exu_i0_br_start_error_r.value = 0 cocotb.top.exu_i0_br_valid_r.value = 0 cocotb.top.exu_i0_br_mp_r.value = 0 cocotb.top.exu_i0_br_middle_r.value = 0 cocotb.top.exu_i0_br_way_r.value = 0 cocotb.top.dbg_halt_req.value = 0 cocotb.top.dbg_resume_req.value = 0 cocotb.top.ifu_miss_state_idle.value = 0 cocotb.top.lsu_idle_any.value = 0 cocotb.top.dec_div_active.value = 0 cocotb.top.ifu_ic_error_start.value = 0 cocotb.top.ifu_iccm_rd_ecc_single_err.value = 0 cocotb.top.ifu_ic_debug_rd_data.value = 0 cocotb.top.ifu_ic_debug_rd_data_valid.value = 0 cocotb.top.pic_claimid.value = 0 cocotb.top.pic_pl.value = 0 cocotb.top.mhwakeup.value = 0 cocotb.top.mexintpend.value = 0 cocotb.top.timer_int.value = 0 cocotb.top.soft_int.value = 0 cocotb.top.core_id.value = 0 cocotb.top.mpc_debug_halt_req.value = 0 cocotb.top.mpc_debug_run_req.value = 0 cocotb.top.mpc_reset_run_req.value = 0 # Start clocks self.start_clock("free_l2clk") self.start_clock("clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/dma/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_dma_ctrl CM_FILE = cm.cfg VERILOG_SOURCES = \ $(SRCDIR)/el2_dma_ctrl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/dma/cm.cfg ================================================ +tree el2_dma_ctrl // 'start_addr' and 'region' are tied to module parameters -node el2_dma_ctrl.*rangecheck.start_addr -node el2_dma_ctrl.*rangecheck.region ================================================ FILE: verification/block/dma/scoreboards.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import struct from collections import defaultdict from pyuvm import ConfigDB, uvm_component, uvm_get_port, uvm_tlm_analysis_fifo from testbench import ( BusReadItem, BusWriteItem, DebugReadItem, DebugWriteItem, MemReadItem, MemWriteItem, ) # ============================================================================= class ReadScoreboard(uvm_component): """ A scoreboard that counts reads that happen on the debug/AXI and memory sides of the DMA module """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None self.iccm_base = ConfigDB().get(None, "", "ICCM_BASE") self.iccm_size = ConfigDB().get(None, "", "ICCM_SIZE") self.dccm_base = ConfigDB().get(None, "", "DCCM_BASE") self.dccm_size = ConfigDB().get(None, "", "DCCM_SIZE") def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def is_iccm(self, addr): return addr >= self.iccm_base and addr < (self.iccm_base + self.iccm_size) def is_dccm(self, addr): return addr >= self.dccm_base and addr < (self.dccm_base + self.dccm_size) def check_phase(self): iccm_reads = defaultdict(lambda: 0) dccm_reads = defaultdict(lambda: 0) # Process writes while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Initially pass if self.passed is None: self.passed = True # AXI read. Check and decode its address if isinstance(item, BusReadItem): # FIXME: Assuming the transaction is 64-bit wide data = struct.unpack("= 3: # FIXME: Unclear data = item.data else: self.logger.error("Invalid transaction size {}".format(item.size)) self.passed = False if item.mem == "ICCM": iccm_reads[ ( item.addr, data, ) ] += 1 elif item.mem == "DCCM": dccm_reads[ ( item.addr, data, ) ] += 1 else: self.logger.error("Read from an unknown memory region '{}'".format(item.mem)) self.passed = False # Check if there is an even number of reads for (each address, data) # for each memory region. for name, d in [("ICCM", iccm_reads), ("DCCM", dccm_reads)]: for key, count in d.items(): if count & 1: self.logger.error( "{} read count from 0x{:08X} is odd, data {}".format(name, key[0], key[1]) ) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================= class WriteScoreboard(uvm_component): """ A scoreboard that counts writes that happen on the debug/AXI and memory sides of the DMA module. """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None self.iccm_base = ConfigDB().get(None, "", "ICCM_BASE") self.iccm_size = ConfigDB().get(None, "", "ICCM_SIZE") self.dccm_base = ConfigDB().get(None, "", "DCCM_BASE") self.dccm_size = ConfigDB().get(None, "", "DCCM_SIZE") def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def is_iccm(self, addr): return addr >= self.iccm_base and addr < (self.iccm_base + self.iccm_size) def is_dccm(self, addr): return addr >= self.dccm_base and addr < (self.dccm_base + self.dccm_size) def check_phase(self): iccm_writes = defaultdict(lambda: 0) dccm_writes = defaultdict(lambda: 0) # Process writes while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Initially pass if self.passed is None: self.passed = True # AXI write. Check and decode its address if isinstance(item, BusWriteItem): # FIXME: Assuming the transaction is 64-bit wide data = struct.unpack("= 3: # FIXME: Unclear data = item.data else: self.logger.error("Invalid transaction size {}".format(item.size)) self.passed = False if item.mem == "ICCM": assert item.addr >= 0 and item.addr < self.iccm_size iccm_writes[ ( item.addr, data, ) ] += 1 elif item.mem == "DCCM": assert item.addr >= 0 and item.addr < self.dccm_size dccm_writes[ ( item.addr, data, ) ] += 1 else: self.logger.error("Write to an unknown memory region '{}'".format(item.mem)) self.passed = False # Check if there is an even number of writes for (each address, data) # for each memory region. for name, d in [("ICCM", iccm_writes), ("DCCM", dccm_writes)]: for key, count in d.items(): if count & 1: self.logger.error( "{} write count to 0x{:08X} is odd, data {}".format(name, key[0], key[1]) ) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================= class AccessScoreboard(uvm_component): """ Checks if all Debug/AXI transfers fail with response 0x3 and that there is no activity on the ICCM/DCCM memory bus """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): # Process items while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Initially pass if self.passed is None: self.passed = True # Got a memory bus activity which is incorrect if isinstance(item, MemReadItem) or isinstance(item, MemWriteItem): self.logger.debug("Unexpected memory access at 0x{:08X}".format(item.address)) self.passed = False # Got an AXI activity, check the response code elif isinstance(item, BusReadItem) or isinstance(item, BusWriteItem): if item.resp != 0x3: self.logger.debug( "Unexpected AXI response (0b{:03b}) for access to 0x{:08X}".format( item.resp, item.address ) ) self.passed = False # Got a debug bus activity, check for failure elif isinstance(item, DebugReadItem) or isinstance(item, DebugWriteItem): if not item.fail: self.logger.debug( "Unexpected debug bus response (0b{:01b}) for access to 0x{:08X}".format( item.fail, item.address ) ) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False ================================================ FILE: verification/block/dma/sequences.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import struct import cocotb from cocotb.triggers import ClockCycles from pyuvm import ConfigDB, uvm_sequence from testbench import BusReadItem, BusWriteItem # ============================================================================= class MemWriteSequence(uvm_sequence): """ A sequence of random memory writes """ def __init__(self, name, mem, dwidth=32): super().__init__(name) self.mem = mem self.dwidth = dwidth async def body(self): mem_base = ConfigDB().get(None, "", self.mem + "_BASE") mem_size = ConfigDB().get(None, "", self.mem + "_SIZE") align = ConfigDB().get(None, "", "ADDR_ALIGN") count = ConfigDB().get(None, "", "TEST_ITERATIONS") burst = ConfigDB().get(None, "", "TEST_BURST_LEN") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for j in range(count): for i in range(burst): addr = mem_base + random.randrange(0, mem_size) addr = (addr // align) * align # Determine how to pack data to bytes if self.dwidth == 32: fmt = "= iccm_base and addr < iccm_base + iccm_size: continue if addr >= dccm_base and addr < dccm_base + dccm_size: continue if addr >= pic_base and addr < pic_base + pic_size: continue break # Randomize read/write if random.random() >= 0.5: item = BusReadItem(addr) else: # Determine how to pack data to bytes if self.dwidth == 32: fmt = " # SPDX-License-Identifier: Apache-2.0 import pyuvm from scoreboards import AccessScoreboard from sequences import InvalidAddressSequence from testbench import BaseEnv, BaseTest # ============================================================================= class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = AccessScoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.axi_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================= @pyuvm.test() class TestAddressOutOfRange(BaseTest): """ Out of range addressing test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = InvalidAddressSequence("stimulus", dwidth=self.env.axi_bfm.dwidth) async def run(self): await self.seq.start(self.env.axi_seqr) ================================================ FILE: verification/block/dma/test_debug_address.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from scoreboards import AccessScoreboard from sequences import InvalidAddressSequence from testbench import BaseEnv, BaseTest # ============================================================================= class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = AccessScoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.dbg_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================= @pyuvm.test() class TestAddressOutOfRange(BaseTest): """ Out of range addressing test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = InvalidAddressSequence("stimulus", dwidth=32) # The debug bus is 32-bit wide async def run(self): await self.seq.start(self.env.dbg_seqr) ================================================ FILE: verification/block/dma/test_debug_read.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from scoreboards import ReadScoreboard from sequences import AnyMemReadSequence, MemReadSequence from testbench import BaseEnv, BaseTest # ============================================================================= class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = ReadScoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.dbg_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================= @pyuvm.test() class TestDCCMRead(BaseTest): """ DCCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = MemReadSequence("stimulus", "DCCM") async def run(self): await self.seq.start(self.env.dbg_seqr) @pyuvm.test() class TestICCMRead(BaseTest): """ ICCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = MemReadSequence("stimulus", "ICCM") async def run(self): await self.seq.start(self.env.dbg_seqr) @pyuvm.test() class TestBothRead(BaseTest): """ Randomized DCCM/ICCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = AnyMemReadSequence("stimulus") async def run(self): await self.seq.start(self.env.dbg_seqr) ================================================ FILE: verification/block/dma/test_debug_write.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from scoreboards import WriteScoreboard from sequences import AnyMemWriteSequence, MemWriteSequence from testbench import BaseEnv, BaseTest # ============================================================================= class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = WriteScoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.dbg_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================= @pyuvm.test() class TestDCCMWrite(BaseTest): """ DCCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = MemWriteSequence("stimulus", "DCCM", dwidth=32) async def run(self): await self.seq.start(self.env.dbg_seqr) @pyuvm.test() class TestICCMWrite(BaseTest): """ ICCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = MemWriteSequence("stimulus", "ICCM", dwidth=32) async def run(self): await self.seq.start(self.env.dbg_seqr) @pyuvm.test() class TestBothWrite(BaseTest): """ Randomized DCCM/ICCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = AnyMemWriteSequence("stimulus", dwidth=32) async def run(self): await self.seq.start(self.env.dbg_seqr) ================================================ FILE: verification/block/dma/test_ecc.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 from collections import defaultdict import pyuvm from pyuvm import ConfigDB, uvm_component, uvm_get_port, uvm_tlm_analysis_fifo from sequences import AnyMemReadSequence from testbench import BaseEnv, BaseTest, BusReadItem, MemReadItem # ============================================================================= class Scoreboard(uvm_component): """ """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None self.iccm_base = ConfigDB().get(None, "", "ICCM_BASE") self.iccm_size = ConfigDB().get(None, "", "ICCM_SIZE") self.dccm_base = ConfigDB().get(None, "", "DCCM_BASE") self.dccm_size = ConfigDB().get(None, "", "DCCM_SIZE") def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def is_iccm(self, addr): return addr > self.iccm_base and addr < (self.iccm_base + self.iccm_size) def is_dccm(self, addr): return addr > self.dccm_base and addr < (self.dccm_base + self.dccm_size) def check_phase(self): reads = defaultdict(lambda: dict()) # Process writes while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Initially pass if self.passed is None: self.passed = True # AXI read. Check and decode its address if isinstance(item, BusReadItem): addr = item.addr reads[addr]["axi"] = item.resp # Memory read elif isinstance(item, MemReadItem): if item.mem == "ICCM": addr = item.addr + self.iccm_base reads[addr]["mem"] = item.resp elif item.mem == "DCCM": addr = item.addr + self.dccm_base reads[addr]["mem"] = item.resp else: self.logger.error("Read from an unknown memory region '{}'".format(item.mem)) self.passed = False # Check reads have_ecc_err = False have_ecc_ok = False for addr, pair in reads.items(): if "axi" not in pair: self.logger.error("No AXI transfer for access to 0x{:08X}".format(addr)) self.passed = False if "mem" not in pair: self.logger.error("No memory transfer for access to 0x{:08X}".format(addr)) self.passed = False if "axi" not in pair or "mem" not in pair: continue # Check correlation between AXI response and ECC error injection if not pair["mem"] and pair["axi"] != 0x0: self.logger.error( "AXI transfer error (0b{:03b}) for access to 0x{:08X}".format(pair["axi"], addr) ) self.passed = False if pair["mem"] and pair["axi"] != 0x2: self.logger.error( "Invalid AXI response (0b{:03b}) for access to 0x{:08X}".format( pair["axi"], addr ) ) self.passed = False # Check if there were errors injected if pair["mem"]: have_ecc_err = True else: have_ecc_ok = True if not have_ecc_err: self.logger.error("There were no ECC errors injected!") self.passed = False if not have_ecc_ok: self.logger.error("There were only ECC errors injected!") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================= class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Enable ECC error injection ConfigDB().set(self.mem_bfm, "", "ECC_ERROR_RATE", 0.5) # Add scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.axi_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================= @pyuvm.test() class TestEccError(BaseTest): """ Tests the DMA reaction on ICCM/DCCM ECC error """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = AnyMemReadSequence("stimulus") async def run(self): await self.seq.start(self.env.axi_seqr) ================================================ FILE: verification/block/dma/test_read.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from scoreboards import ReadScoreboard from sequences import AnyMemReadSequence, MemReadSequence from testbench import BaseEnv, BaseTest # ============================================================================= class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = ReadScoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.axi_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================= @pyuvm.test() class TestDCCMRead(BaseTest): """ DCCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = MemReadSequence("stimulus", "DCCM") async def run(self): await self.seq.start(self.env.axi_seqr) @pyuvm.test() class TestICCMRead(BaseTest): """ ICCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = MemReadSequence("stimulus", "ICCM") async def run(self): await self.seq.start(self.env.axi_seqr) @pyuvm.test() class TestBothRead(BaseTest): """ Randomized DCCM/ICCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = AnyMemReadSequence("stimulus") async def run(self): await self.seq.start(self.env.axi_seqr) ================================================ FILE: verification/block/dma/test_reset.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import cocotb import pyuvm from testbench import BaseTest # ============================================================================= @pyuvm.test() class TestReset(BaseTest): """ A basic test that resets the DUT """ async def run(self): # Check state of DUT signals after reset state = { "dma_dbg_cmd_done": 0, "dma_dbg_cmd_fail": 0, "dma_dccm_req": 0, "dma_iccm_req": 0, "dma_active": 0, "dma_dccm_stall_any": 0, "dma_iccm_stall_any": 0, "dma_pmu_dccm_read": 0, "dma_pmu_dccm_write": 0, "dma_pmu_any_read": 0, "dma_pmu_any_write": 0, "dma_axi_bvalid": 0, "dma_axi_rvalid": 0, } for name, value in state.items(): signal = getattr(cocotb.top, name) assert signal.value == value, "{}={}, should be {}".format(name, signal.value, value) ================================================ FILE: verification/block/dma/test_write.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from scoreboards import WriteScoreboard from sequences import AnyMemWriteSequence, MemWriteSequence from testbench import BaseEnv, BaseTest # ============================================================================= class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = WriteScoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.axi_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================= @pyuvm.test() class TestDCCMWrite(BaseTest): """ DCCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = MemWriteSequence("stimulus", "DCCM", dwidth=self.env.axi_bfm.dwidth) async def run(self): await self.seq.start(self.env.axi_seqr) @pyuvm.test() class TestICCMWrite(BaseTest): """ ICCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = MemWriteSequence("stimulus", "ICCM", dwidth=self.env.axi_bfm.dwidth) async def run(self): await self.seq.start(self.env.axi_seqr) @pyuvm.test() class TestBothWrite(BaseTest): """ Randomized DCCM/ICCM write test """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = AnyMemWriteSequence("stimulus", dwidth=self.env.axi_bfm.dwidth) async def run(self): await self.seq.start(self.env.axi_seqr) ================================================ FILE: verification/block/dma/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import logging import math import os import random import struct import cocotb from axi import Axi4LiteMonitor, BusReadItem, BusWriteItem from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge, Lock, ReadOnly, RisingEdge from pyuvm import ( ConfigDB, uvm_analysis_port, uvm_component, uvm_driver, uvm_env, uvm_report_object, uvm_sequence_item, uvm_sequencer, uvm_test, ) from utils import collect_bytes, collect_signals, smallest_number_of_trials # ============================================================================== class MemWriteItem(uvm_sequence_item): """ A generic memory bus write item """ def __init__(self, mem, addr, data, size=64, resp=None): super().__init__("MemWriteItem") self.mem = mem self.addr = addr self.data = data self.size = size self.resp = resp class MemReadItem(uvm_sequence_item): """ A generic memory bus read item """ def __init__(self, mem, addr, data, size=64, resp=None): super().__init__("MemReadItem") self.mem = mem self.addr = addr self.data = data self.size = size self.resp = resp class DebugWriteItem(uvm_sequence_item): """ A debug bus write item """ def __init__(self, addr, data, size=32, fail=False): super().__init__("DebugWriteItem") self.addr = addr self.data = data self.size = size self.fail = fail class DebugReadItem(uvm_sequence_item): """ A debug bus read item """ def __init__(self, addr, data=None, size=32, fail=False): super().__init__("DebugReadItem") self.addr = addr self.data = data self.size = size self.fail = fail # ============================================================================== class CoreMemoryBFM(uvm_component): """ A BFM for the memory side interface of the DMA module """ SIGNALS = [ "clk", "dma_dccm_req", "dma_iccm_req", "dma_mem_tag", "dma_mem_addr", "dma_mem_sz", "dma_mem_write", "dma_mem_wdata", "dccm_dma_rvalid", "dccm_dma_ecc_error", "dccm_dma_rtag", "dccm_dma_rdata", "iccm_dma_rvalid", "iccm_dma_ecc_error", "iccm_dma_rtag", "iccm_dma_rdata", "dccm_ready", "iccm_ready", ] def __init__(self, name, parent, uut): super().__init__(name, parent) # Collect signals collect_signals(self.SIGNALS, uut, self) # Memory content self.iccm_data = dict() self.dccm_data = dict() def build_phase(self): # Get base addresses and sizes self.iccm_base = ConfigDB().get(None, "", "ICCM_BASE") self.dccm_base = ConfigDB().get(None, "", "DCCM_BASE") self.iccm_size = ConfigDB().get(None, "", "ICCM_SIZE") self.dccm_size = ConfigDB().get(None, "", "DCCM_SIZE") # Get parameters self.iccm_busy = ConfigDB().get(self, "", "ICCM_BUSY_PROB") self.dccm_busy = ConfigDB().get(self, "", "DCCM_BUSY_PROB") self.busy_range = ( ConfigDB().get(self, "", "MEM_BUSY_MIN"), ConfigDB().get(self, "", "MEM_BUSY_MAX"), ) self.ecc_err_rate = ConfigDB().get(self, "", "ECC_ERROR_RATE") async def iccm_busy_task(self): """ A task that randomly makes ICCM busy """ while True: await RisingEdge(self.clk) # Become busy at random for a random cycle count if random.random() < self.iccm_busy: self.iccm_ready.value = 0 n = random.randrange(*self.busy_range) await ClockCycles(self.clk, n) self.iccm_ready.value = 1 async def dccm_busy_task(self): """ A task that randomly makes DCCM busy """ while True: await RisingEdge(self.clk) # Become busy at random for a random cycle count if random.random() < self.dccm_busy: self.dccm_ready.value = 0 n = random.randrange(*self.busy_range) await ClockCycles(self.clk, n) self.dccm_ready.value = 1 async def responder(self): """ A task for handling read / write responses """ while True: await RisingEdge(self.clk) # Sample signals tag = int(self.dma_mem_tag) # DCCM access if self.dma_dccm_req.value: # Decode and check address addr = int(self.dma_mem_addr.value) - self.dccm_base assert addr >= 0 and addr < self.dccm_size # Write / read if self.dma_mem_write.value: self.dccm_data[addr] = int(self.dma_mem_wdata.value) else: if addr not in self.dccm_data: self.dccm_data[addr] = random.randrange(0, (1 << 64) - 1) self.dccm_dma_rdata.value = self.dccm_data[addr] self.dccm_dma_rtag.value = tag self.dccm_dma_rvalid.value = 1 self.dccm_dma_ecc_error.value = random.random() < self.ecc_err_rate await RisingEdge(self.clk) self.dccm_dma_rvalid.value = 0 # ICCM access elif self.dma_iccm_req.value: # Decode and check address addr = int(self.dma_mem_addr.value) - self.iccm_base assert addr >= 0 and addr < self.iccm_size # Write / read if self.dma_mem_write.value: self.iccm_data[addr] = int(self.dma_mem_wdata.value) else: if addr not in self.iccm_data: self.iccm_data[addr] = random.randrange(0, (1 << 64) - 1) self.iccm_dma_rdata.value = self.iccm_data[addr] self.iccm_dma_rtag.value = tag self.iccm_dma_rvalid.value = 1 self.iccm_dma_ecc_error.value = random.random() < self.ecc_err_rate await RisingEdge(self.clk) self.iccm_dma_rvalid.value = 0 async def run_phase(self): # Initially make ICCM and DCCM ready self.iccm_ready.value = 1 self.dccm_ready.value = 1 # Start tasks cocotb.start_soon(self.iccm_busy_task()) cocotb.start_soon(self.dccm_busy_task()) cocotb.start_soon(self.responder()) class CoreMemoryMonitor(uvm_component): """ A monitor for ICCM / DCCM interface """ def __init__(self, *args, **kwargs): self.bfm = kwargs["bfm"] del kwargs["bfm"] super().__init__(*args, **kwargs) # Get base addresses self.iccm_base = ConfigDB().get(None, "", "ICCM_BASE") self.dccm_base = ConfigDB().get(None, "", "DCCM_BASE") def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): req_pending = False is_iccm = False is_dccm = False req_wr = False req_addr = 0 req_data = 0 req_size = 0 while True: await RisingEdge(self.bfm.clk) await ReadOnly() # Monitor reads which happen one cycle after a request if req_pending and not req_wr: if is_iccm: addr = req_addr - self.iccm_base data = int(self.bfm.iccm_dma_rdata.value) resp = int(self.bfm.iccm_dma_ecc_error.value) self.ap.write(MemReadItem("ICCM", addr, data, req_size, resp)) self.logger.debug("ICCM RD: 0x{:08X} 0x{:016X} {}".format(addr, data, resp)) if is_dccm: addr = req_addr - self.dccm_base data = int(self.bfm.dccm_dma_rdata.value) resp = int(self.bfm.dccm_dma_ecc_error.value) self.ap.write(MemReadItem("DCCM", addr, data, req_size, resp)) self.logger.debug("DCCM RD: 0x{:08X} 0x{:016X} {}".format(addr, data, resp)) req_pending = False # We have a request is_iccm = self.bfm.dma_iccm_req.value is_dccm = self.bfm.dma_dccm_req.value if is_iccm or is_dccm: req_pending = True req_addr = int(self.bfm.dma_mem_addr.value) req_data = int(self.bfm.dma_mem_wdata.value) req_wr = int(self.bfm.dma_mem_write.value) req_size = int(self.bfm.dma_mem_sz.value) # Writes if req_wr and is_iccm: addr = req_addr - self.iccm_base self.ap.write(MemWriteItem("ICCM", addr, req_data, req_size)) self.logger.debug("ICCM WR: 0x{:08X} 0x{:016X}".format(addr, req_data)) if req_wr and is_dccm: addr = req_addr - self.dccm_base self.ap.write(MemWriteItem("DCCM", addr, req_data, req_size)) self.logger.debug("DCCM WR: 0x{:08X} 0x{:016X}".format(addr, req_data)) # ============================================================================== class Axi4LiteBFM(uvm_component): """ A bus functional model for AXI4 Lite subordinate port. Does support multi-transfer transactions, supports overlapped transactions for writes """ SIGNALS = [ "clk", "rst", "awvalid", "awready", "awid", "awaddr", "awsize", "wvalid", "wready", "wdata", "wstrb", "bvalid", "bready", "bresp", "bid", "arvalid", "arready", "arid", "araddr", "arsize", "rvalid", "rready", "rid", "rdata", "rresp", "rlast", ] class Transfer: """ Represents a pending AXI transfer """ def __init__(self, tid): self.tid = tid self.addr = None self.data = None self.pending = False def __init__(self, name, parent, uut, signal_map): super().__init__(name, parent) # Collect signals collect_signals( self.SIGNALS, uut, self, uut_prefix="dma_axi_", obj_prefix="axi_", signal_map=signal_map ) # Determine bus parameters self.awidth = len(self.axi_awaddr) self.dwidth = len(self.axi_wdata) self.swidth = len(self.axi_wstrb) assert self.swidth == (self.dwidth // 8) self.logger.debug("AXI4 Lite BFM:") self.logger.debug(" awidth = {}".format(self.awidth)) self.logger.debug(" dwidth = {}".format(self.dwidth)) self.logger.debug(" swidth = {}".format(self.swidth)) self.xfer_lock = Lock() self.wr_xfers = {i: self.Transfer(i) for i in range(1 << len(self.axi_awid))} def build_phase(self): self.busy_timeout = ConfigDB().get(self, "", "MEM_BUSY_TIMEOUT") async def _wait(self, signal, max_cycles=200): """ Waits for a signal to be asserted in at most max_cycles. Raises an exception if it does not """ for _ in range(max_cycles): await RisingEdge(self.axi_clk) if signal.value != 0: break else: raise RuntimeError("{} timeout".format(signal._name)) async def write(self, addr, data): """ Issues a write transfer, does not wait until it completes """ # Wait for a free transfer id while True: await RisingEdge(self.axi_clk) async with self.xfer_lock: awid = None for tid, xfr in self.wr_xfers.items(): if not xfr.pending: awid = tid break if awid is not None: xfer = self.wr_xfers[awid] xfer.pending = True xfer.addr = addr xfer.data = data break # Send write request self.axi_awvalid.value = 1 self.axi_awaddr.value = addr self.axi_awid.value = awid self.axi_awsize.value = int(math.ceil(math.log2(self.dwidth))) await self._wait(self.axi_awready, self.busy_timeout) self.axi_awvalid.value = 0 # Send data self.axi_wvalid.value = 1 data_len = len(data) data_ptr = 0 while data_len > 0: # Get data xfer_len = min(self.swidth, data_len) xfer_data = data[data_ptr : data_ptr + xfer_len] data_ptr += xfer_len data_len -= xfer_len # Assert data wdata = 0 wstrb = 0 for i in range(xfer_len): wdata <<= 8 wstrb <<= 1 wdata |= xfer_data[-(1 + i)] wstrb |= 1 self.axi_wdata.value = wdata self.axi_wstrb.value = wstrb await self._wait(self.axi_wready, self.busy_timeout) self.axi_wvalid.value = 0 async def write_handler(self): """ A handler for write transfer completion """ # Accept responses self.axi_bready.value = 1 while True: # Wait for response await RisingEdge(self.axi_clk) if not self.axi_bvalid.value: continue bresp = int(self.axi_bresp.value) bid = int(self.axi_bid.value) # Find a pending transfer async with self.xfer_lock: xfer = self.wr_xfers.get(bid, None) if not xfer: self.logger.error("Write response for a non-pending tid {}".format(bid)) continue xfer.pending = False addr = xfer.addr data = xfer.data self.logger.debug( "WR: 0x{:08X} {} 0b{:03b}".format(addr, ["0x{:02X}".format(b) for b in data], bresp) ) async def read(self, addr, data): """ Issues a read transfer and waits for its completion """ # Send read request self.axi_araddr.value = addr self.axi_arid.value = 1 self.axi_arsize.value = int(math.ceil(math.log2(self.dwidth))) self.axi_arvalid.value = 1 await self._wait(self.axi_arready, self.busy_timeout) self.axi_arvalid.value = 0 self.axi_rready.value = 1 data = bytearray() rresp = None while True: # Receive data await self._wait(self.axi_rvalid, self.busy_timeout) # Get the data data.extend(collect_bytes(self.axi_rdata)) # Last, finish reception if self.axi_rlast.value: break rresp = int(self.axi_rresp.value) self.axi_rready.value = 0 self.logger.debug( "RD: 0x{:08X} {} 0b{:03b}".format(addr, ["0x{:02X}".format(b) for b in data], rresp) ) return bytes(data), rresp async def run_phase(self): # Start read & write handlers cocotb.start_soon(self.write_handler()) # ============================================================================== class Axi4LiteSubordinateDriver(uvm_driver): """ A driver component for AXI4 lite subordinate ports. Acts as an AXI Manager. """ def __init__(self, *args, **kwargs): self.bfm = kwargs["bfm"] del kwargs["bfm"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, BusWriteItem): await self.bfm.write(it.addr, it.data) elif isinstance(it, BusReadItem): # FIXME: Assuming that all read requests are 64-bit wide await self.bfm.read(it.addr, 8) else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() # ============================================================================== class DebugInterfaceBFM(uvm_component): """ A DFM for DMA debug interface """ SIGNALS = [ "clk", "dbg_cmd_addr", "dbg_cmd_wrdata", "dbg_cmd_valid", "dbg_cmd_write", "dbg_cmd_type", "dbg_cmd_size", "dbg_dma_bubble", "dma_dbg_ready", "dma_dbg_cmd_done", "dma_dbg_cmd_fail", "dma_dbg_rddata", ] def __init__(self, name, parent, uut): super().__init__(name, parent) # Collect signals collect_signals(self.SIGNALS, uut, self) def build_phase(self): self.busy_prob = ConfigDB().get(self, "", "DBG_BUSY_PROB") self.busy_range = ( ConfigDB().get(self, "", "DBG_BUSY_MIN"), ConfigDB().get(self, "", "DBG_BUSY_MAX"), ) self.busy_timeout = ConfigDB().get(self, "", "DBG_BUSY_TIMEOUT") async def _wait(self, signal, max_cycles=150): """ Waits for a signal to be asserted for at most max_cycles. Raises an exception if it does not """ for i in range(max_cycles): await RisingEdge(self.clk) if signal.value != 0: break else: raise RuntimeError("{} timeout".format(signal._name)) async def write(self, addr, data): """ Performs a debug interface write. Waits for completion and returns status code """ # Wait for ready await self._wait(self.dma_dbg_ready, self.busy_timeout) # Issue the command self.dbg_cmd_valid.value = 1 self.dbg_cmd_write.value = 1 self.dbg_cmd_size.value = 2 # Apparently 0=8, 1=16, 2=32 self.dbg_cmd_addr.value = addr self.dbg_cmd_wrdata.value = struct.unpack(" Driver <---> Top module Monitor <------^ """ def build_phase(self): self.seqr = uvm_sequencer("seqr", self) ConfigDB().set(None, "*", "DMI_SEQR", self.seqr) self.monitor = DMIMonitor("dmi_monitor", self, "rsp_monitor_q_get") self.driver = DMIDriver("dmi_driver", self) def connect_phase(self): self.driver.seq_item_port.connect(self.seqr.seq_item_export) class DMIDriver(uvm_driver): def build_phase(self): self.ap = uvm_analysis_port("ap_drv", self) def start_of_simulation_phase(self): self.bfm = BFM() async def run_phase(self): self.bfm.start_bfm() while True: item = await self.seq_item_port.get_next_item() await self.bfm.req_driver_q_put(item) self.seq_item_port.item_done() class DMIMonitor(uvm_component): def __init__(self, name, parent, method_name): super().__init__(name, parent) self.method_name = method_name def build_phase(self): self.ap = uvm_analysis_port("ap_mon", self) self.bfm = BFM() self.get_method = getattr(self.bfm, self.method_name) async def run_phase(self): while True: datum = await self.get_method() self.logger.debug(f"DMI Monitor req: {datum}") self.ap.write(datum) ================================================ FILE: verification/block/dmi/dmi_bfm.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from cocotb.triggers import FallingEdge, RisingEdge from dmi_seq import SetUncoreEnableSeqItem from pyuvm import * from common import Defaults, collect_signals, get_int class MemoryModel: def __init__(self): self.memory = {} self.reset() def write(self, addr, data): self.memory.update({addr: data}) def read(self, addr): return get_int(self.memory.setdefault(addr, 0)) def reset(self): self.memory = { 0x01: Defaults.JTAG_ID, 0x10: Defaults.DTMCS, 0x11: 0, } class DMITestBfm(metaclass=utility_classes.Singleton): """ A BFM for the DMI core module. """ SIGNALS = [ # Control inputs "core_rst_n", "core_clk", "jtag_id", # DMI inputs "uncore_enable", "dmi_core_rdata", "dmi_uncore_rdata", # DMI outputs "dmi_hard_reset", "rd_data", "dmi_core_en", "dmi_core_wr_en", "dmi_core_addr", "dmi_core_wdata", "dmi_uncore_en", "dmi_uncore_wr_en", "dmi_uncore_addr", "dmi_uncore_wdata", ] def __init__(self): self.dut = cocotb.top self.req_driver_q = UVMQueue(maxsize=1) self.req_monitor_q = UVMQueue(maxsize=0) self.rsp_monitor_q = UVMQueue(maxsize=0) self.predictor = ConfigDB().get(None, "", "JTAG_PREDICTOR") self.core_mem = MemoryModel() self.uncore_mem = MemoryModel() collect_signals(self.SIGNALS, self.dut, self) self.rst_n = self.core_rst_n self.clk = self.core_clk async def req_driver_q_put(self, item): await self.req_driver_q.put(item) async def rsp_monitor_q_get(self): result = await self.rsp_monitor_q.get() return result async def driver_bfm(self): """ Reads a register """ self.dmi_core_rdata.value = 0 self.dmi_uncore_rdata.value = 0 self.uncore_enable.value = 0 self.jtag_id.value = Defaults.JTAG_ID while True: await FallingEdge(self.clk) try: item = self.req_driver_q.get_nowait() if isinstance(item, SetUncoreEnableSeqItem): self.uncore_enable.value = item.uncore_enable except QueueEmpty: pass async def rsp_monitor_q_bfm(self): DMI_CORE_BOUNDARY = 0x4F await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: await RisingEdge(self.rst_n) await RisingEdge(self.clk) if self.dmi_hard_reset.value: self.core_mem.reset() self.uncore_mem.reset() pass # DMI Core memory managment if self.dmi_core_en.value: self.dmi_core_rdata.value = self.core_mem.read(get_int(self.dmi_core_addr)) if self.dmi_core_wr_en.value: self.core_mem.write(get_int(self.dmi_core_addr), get_int(self.dmi_core_wdata)) # DMI Uncore memory managment if self.dmi_uncore_en.value: self.dmi_uncore_rdata.value = self.uncore_mem.read(get_int(self.dmi_uncore_addr)) if self.dmi_uncore_wr_en.value: self.uncore_mem.write(get_int(self.dmi_uncore_addr), get_int(self.dmi_uncore_wdata)) # Pass data to the scoreboard on write/read request if self.dmi_uncore_en.value or self.dmi_core_en.value: if (self.predictor.wr_addr.integer > DMI_CORE_BOUNDARY) and self.uncore_enable: dmi_type = "uncore" values = [ get_int(self.rd_data), get_int(self.dmi_uncore_rdata), get_int(self.dmi_uncore_addr), get_int(self.dmi_uncore_en), get_int(self.predictor.rd_en), ] else: dmi_type = "core" values = [ get_int(self.rd_data), get_int(self.dmi_core_rdata), get_int(self.dmi_core_addr), get_int(self.dmi_core_en), get_int(self.predictor.rd_en), ] self.rsp_monitor_q.put_nowait((values, dmi_type)) def start_bfm(self): cocotb.start_soon(self.driver_bfm()) cocotb.start_soon(self.rsp_monitor_q_bfm()) ================================================ FILE: verification/block/dmi/dmi_seq.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from cocotb.handle import LogicArray from jtag_seq import * from pyuvm import * class SetUncoreEnableSeqItem(uvm_sequence_item): def __init__(self, name, uncore_enable): super().__init__(name) self.uncore_enable = uncore_enable def __str__(self): return self.__class__.__name__ def randomize(self): pass class SetUncoreEnableSequence(BaseSeq): def __init__(self, name, value): super().__init__(name) self.name = name self.value = value async def body(self): item = [SetUncoreEnableSeqItem(self.name, self.value)] await self.run_items(item) class AccessDMIRegSequence(BaseSeq): def __init__(self, name, addr, data=0x0, is_write=False): super().__init__(name) assert isinstance(addr, int) assert isinstance(data, int) self.addr = LogicArray(addr, range(7)) self.data = LogicArray(data, range(32)) self.is_write = 1 if is_write else 0 async def body(self): data_bits_items = [] addr_bits_items = [] for i, val in enumerate(reversed(list(self.data))): data_bits_items.append(JTAGBaseSeqItem("write_data_bit{}".format(i), 0, val)) for i, val in enumerate(reversed(list(self.addr))): # Last bit must be written simultaneously with leaving SHIFT_DR state tms = 1 if (i == (len(list(self.addr)) - 1)) else 0 addr_bits_items.append(JTAGBaseSeqItem("write_addr_bit{}".format(i), tms, val)) items = [ JTAGBaseSeqItem("switch_to_select_dr_scan", 1, 0), JTAGBaseSeqItem("switch_to_capture_dr", 0, 0), JTAGBaseSeqItem("switch_to_shift_dr", 0, 0), JTAGBaseSeqItem("write_rd_en_bit", 0, 1), JTAGBaseSeqItem("write_wr_en_bit", 0, self.is_write), ] items += data_bits_items items += addr_bits_items items += [ JTAGBaseSeqItem("switch_to_update_dr", 1, 0), JTAGBaseSeqItem("switch_to_idle", 0, 0), JTAGBaseSeqItem("idle0", 0, 0), JTAGBaseSeqItem("idle1", 0, 0), ] await self.run_items(items) ================================================ FILE: verification/block/dmi/dmi_test_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module dmi_test_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( // JTAG signals input trst_n, // JTAG reset input tck, // JTAG clock input tms, // Test mode select input tdi, // Test Data Input output tdo, // Test Data Output output tdoEnable, // Test Data Output enable // Processor Signals input core_rst_n, // Core reset input core_clk, // Core clock input [31:1] jtag_id, output [31:0] rd_data, // 32 bit Read data from Processor output dmi_hard_reset, // Uncore access enable input wire uncore_enable, // DMI downstream for core output wire dmi_core_en, output wire dmi_core_wr_en, output wire [6:0] dmi_core_addr, output wire [31:0] dmi_core_wdata, input wire [31:0] dmi_core_rdata, // DMI downstream for uncore output wire dmi_uncore_en, output wire dmi_uncore_wr_en, output wire [6:0] dmi_uncore_addr, output wire [31:0] dmi_uncore_wdata, input wire [31:0] dmi_uncore_rdata ); logic [ 6:0] reg_wr_addr; // Reg address to Processor logic [31:0] reg_wr_data; // Reg address to Processor logic reg_en; // Read enable to Processor logic reg_wr_en; // Write enable to Processor logic dmi_en; logic dmi_wr_en; logic [ 6:0] dmi_addr; logic [31:0] dmi_wdata; logic [31:0] dmi_rdata; logic core_enable; assign core_enable = '1; assign dmi_en = reg_en; assign dmi_wr_en = reg_wr_en; assign dmi_addr = reg_wr_addr; assign dmi_wdata = reg_wr_data; assign rd_data = dmi_rdata; dmi_wrapper wrapper (.*); dmi_mux mux (.*); endmodule ================================================ FILE: verification/block/dmi/jtag_agent.py ================================================ from jtag_bfm import JTAGBfm as BFM from pyuvm import * from common import * class JTAGAgent(uvm_agent): """ Seqr <---> Driver <---> Top module Monitor <------^ """ def build_phase(self): self.seqr = uvm_sequencer("seqr", self) ConfigDB().set(None, "*", "JTAG_SEQR", self.seqr) self.monitor = JTAGMonitor("jtag_monitor", self, "rsp_monitor_q_get") self.driver = JTAGDriver("jtag_driver", self) def connect_phase(self): self.driver.seq_item_port.connect(self.seqr.seq_item_export) class JTAGDriver(uvm_driver): def build_phase(self): self.ap = uvm_analysis_port("ap_drv", self) def start_of_simulation_phase(self): self.bfm = BFM() async def run_phase(self): await self.bfm.reset() self.bfm.start_bfm() while True: item = await self.seq_item_port.get_next_item() await self.bfm.req_driver_q_put(item.tms, item.tdi) self.seq_item_port.item_done() class JTAGMonitor(uvm_component): def __init__(self, name, parent, method_name): super().__init__(name, parent) self.method_name = method_name def build_phase(self): self.ap = uvm_analysis_port("ap_mon", self) self.bfm = BFM() self.get_method = getattr(self.bfm, self.method_name) async def run_phase(self): while True: datum = await self.get_method() self.logger.debug(f"JTAG Monitor req: {datum}") self.ap.write(datum) ================================================ FILE: verification/block/dmi/jtag_bfm.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import cocotb import pyuvm from cocotb.triggers import ClockCycles, FallingEdge, ReadOnly, RisingEdge from jtag_pkg import * from pyuvm import * from common import * # ============================================================================= class MemoryModel: def __init__(self): self.memory = {} def write(self, addr, data): self.memory.update({addr, data}) def read(self, addr): self.memory.setdefault(addr, 0) return self.memory.get[addr] def reset(self): self.memory = {} class JTAGBfm(metaclass=utility_classes.Singleton): """ A Bus Functional Model for JTAG TAP. """ SIGNALS = [ # Inputs "trst_n", "tck", "tms", "tdi", # Outputs "tdo", "tdoEnable", ] def __init__(self): self.dut = cocotb.top self.req_driver_q = UVMQueue(maxsize=1) self.req_monitor_q = UVMQueue(maxsize=0) self.rsp_monitor_q = UVMQueue(maxsize=0) self.predictor = ConfigDB().get(None, "", "JTAG_PREDICTOR") collect_signals(self.SIGNALS, self.dut, self) async def req_driver_q_put(self, tms, tdi): item = (tms, tdi) await self.req_driver_q.put(item) async def rsp_monitor_q_get(self): result = await self.rsp_monitor_q.get() return result async def reset(self): await FallingEdge(self.tck) self.trst_n.value = 0 self.tms.value = 1 self.tdi.value = 0 await ClockCycles(self.tck, 10) await FallingEdge(self.tck) self.trst_n.value = 1 await FallingEdge(self.tck) async def driver_bfm(self): sigs = [self.tms, self.tdi] for sig in sigs: sig.value = 0 while True: await FallingEdge(self.tck) try: tms, tdi = self.req_driver_q.get_nowait() self.tms.value = tms self.tdi.value = tdi except QueueEmpty: pass async def req_monitor_q_bfm(self): while True: if self.trst_n.value == 0: await RisingEdge(self.trst_n) await RisingEdge(self.tck) item = (get_int(self.tms), get_int(self.tdi)) self.req_monitor_q.put_nowait(item) async def rsp_monitor_q_bfm(self): while True: if self.trst_n.value == 0: await RisingEdge(self.trst_n) await FallingEdge(self.tck) await ReadOnly() self.predictor.predict_jtag_outputs(edge="neg") await RisingEdge(self.tck) await ReadOnly() self.predictor.predict_jtag_outputs(edge="pos") curr_values = [ get_int(self.tdo), get_int(self.tdoEnable), ] predicted_values = [ get_int(self.predictor.tdo), get_int(self.predictor.tdoEnable), ] self.rsp_monitor_q.put_nowait((curr_values, predicted_values)) def start_bfm(self): cocotb.start_soon(self.driver_bfm()) cocotb.start_soon(self.req_monitor_q_bfm()) cocotb.start_soon(self.rsp_monitor_q_bfm()) ================================================ FILE: verification/block/dmi/jtag_pkg.py ================================================ from enum import IntEnum from cocotb.types import LogicArray, Range class JTAGDefaults: IDLE = LogicArray(0, Range(1, "downto", 0)) DMI_STAT = LogicArray(0, Range(1, "downto", 0)) VERSION = LogicArray(1, Range(3, "downto", 0)) RD_STATUS = LogicArray(0, Range(1, "downto", 0)) class JTAGInstructions: DEVICE_ID_SEL = LogicArray(0b00001, Range(4, "downto", 0)) DR_EN_0 = LogicArray(0b10000, Range(4, "downto", 0)) DR_EN_1 = LogicArray(0b10001, Range(4, "downto", 0)) class JTAGStates(IntEnum): TEST_LOGIC_RESET_STATE = 0 RUN_TEST_IDLE_STATE = 1 SELECT_DR_SCAN_STATE = 2 CAPTURE_DR_STATE = 3 SHIFT_DR_STATE = 4 EXIT1_DR_STATE = 5 PAUSE_DR_STATE = 6 EXIT2_DR_STATE = 7 UPDATE_DR_STATE = 8 SELECT_IR_SCAN_STATE = 9 CAPTURE_IR_STATE = 10 SHIFT_IR_STATE = 11 EXIT1_IR_STATE = 12 PAUSE_IR_STATE = 13 EXIT2_IR_STATE = 14 UPDATE_IR_STATE = 15 ================================================ FILE: verification/block/dmi/jtag_predictor.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import os from cocotb.types import Logic, LogicArray, Range, concat from jtag_pkg import * from common import * class JTAGPredictor: """ A predictor for JTAG TAP that is able to calculate current states of internal FSM, registers and output ports. """ def __init__(self, dut): level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) self.AWIDTH = AWIDTH = ConfigDB().get(None, "", "AWIDTH") self.reg_range = Range(AWIDTH + 33, "downto", 0) self.logger = uvm_root().logger self.logger.setLevel(level) self.dut = dut # Predicted output ports self.tdo = Logic(0) self.tdo_next = Logic(0) self.tdoEnable = Logic(0) self.wr_data = LogicArray(0, Range(31, "downto", 0)) self.wr_addr = LogicArray(0, Range(AWIDTH - 1, "downto", 0)) self.wr_en = Logic(0) self.rd_en = Logic(0) self.dmi_hard_reset = Logic(0) # JTAG input ports self.rd_data = dut.rd_data self.trst_n = dut.trst_n self.tms = dut.tms self.tdi = dut.tdi # Internal JTAG state and registers self.nstate = JTAGStates.TEST_LOGIC_RESET_STATE self.state = self.nstate self.prev_nstate = self.state self.ir = LogicArray(0x1, Range(4, "downto", 0)) self.dr = LogicArray(0x0, self.reg_range) self.ndr = LogicArray(0x0, self.reg_range) self.sr = LogicArray(0x0, self.reg_range) self.nsr = LogicArray(0x0, self.reg_range) def __str__(self): str = "TAP Controller currently in state: {}\n".format(JTAGStates(self.state).name) str += "Expected vs actual outputs:\n" str += "tdo: {} vs {}\n".format(hex(int(self.tdo)), hex(self.dut.tdo.value)) str += "tdoEnable: {} vs {}\n".format( hex(int(self.tdoEnable)), hex(self.dut.tdoEnable.value) ) str += "wr_data: {} vs {}\n".format( hex(self.wr_data.integer), hex(self.dut.reg_wr_data.value) ) str += "wr_addr: {} vs {}\n".format( hex(self.wr_addr.integer), hex(self.dut.reg_wr_addr.value) ) str += "wr_en: {} vs {}\n".format( hex(int(self.wr_en)), hex(self.dut.reg_wr_en.value) ) str += "rd_en: {} vs {}\n".format(hex(int(self.rd_en)), hex(self.dut.reg_en.value)) str += "dmi_hard_reset: {} vs {}".format( hex(int(self.dmi_hard_reset)), hex(self.dut.dmi_hard_reset.value) ) return str def update_state(self): if self.state != self.nstate: self.logger.debug( "Switching state {} to {}".format( JTAGStates(self.state).name, JTAGStates(self.nstate).name, ) ) self.state = self.nstate def update_nstate(self): """ State machine compliant with TAP Controller documentation (IEEE Std 1149.1-2001) and VeeR EL2 specific TAP implementation. """ self.prev_nstate = self.nstate if self.trst_n == 0: self.nstate = JTAGStates.TEST_LOGIC_RESET_STATE pass if self.state == JTAGStates.TEST_LOGIC_RESET_STATE: self.nstate = ( JTAGStates.TEST_LOGIC_RESET_STATE if get_int(self.tms) == 1 else JTAGStates.RUN_TEST_IDLE_STATE ) elif self.state == JTAGStates.RUN_TEST_IDLE_STATE: self.nstate = ( JTAGStates.SELECT_DR_SCAN_STATE if get_int(self.tms) == 1 else JTAGStates.RUN_TEST_IDLE_STATE ) elif self.state == JTAGStates.SELECT_DR_SCAN_STATE: self.nstate = ( JTAGStates.SELECT_IR_SCAN_STATE if get_int(self.tms) == 1 else JTAGStates.CAPTURE_DR_STATE ) elif self.state == JTAGStates.CAPTURE_DR_STATE: self.nstate = ( JTAGStates.EXIT1_DR_STATE if get_int(self.tms) == 1 else JTAGStates.SHIFT_DR_STATE ) elif self.state == JTAGStates.SHIFT_DR_STATE: self.nstate = ( JTAGStates.EXIT1_DR_STATE if get_int(self.tms) == 1 else JTAGStates.SHIFT_DR_STATE ) elif self.state == JTAGStates.EXIT1_DR_STATE: self.nstate = ( JTAGStates.UPDATE_DR_STATE if get_int(self.tms) == 1 else JTAGStates.PAUSE_DR_STATE ) elif self.state == JTAGStates.PAUSE_DR_STATE: self.nstate = ( JTAGStates.EXIT2_DR_STATE if get_int(self.tms) == 1 else JTAGStates.PAUSE_DR_STATE ) elif self.state == JTAGStates.EXIT2_DR_STATE: self.nstate = ( JTAGStates.UPDATE_DR_STATE if get_int(self.tms) == 1 else JTAGStates.SHIFT_DR_STATE ) elif self.state == JTAGStates.UPDATE_DR_STATE: self.nstate = ( JTAGStates.SELECT_DR_SCAN_STATE if get_int(self.tms) == 1 else JTAGStates.RUN_TEST_IDLE_STATE ) elif self.state == JTAGStates.SELECT_IR_SCAN_STATE: self.nstate = ( JTAGStates.TEST_LOGIC_RESET_STATE if get_int(self.tms) == 1 else JTAGStates.CAPTURE_IR_STATE ) elif self.state == JTAGStates.CAPTURE_IR_STATE: self.nstate = ( JTAGStates.EXIT1_IR_STATE if get_int(self.tms) == 1 else JTAGStates.SHIFT_IR_STATE ) elif self.state == JTAGStates.SHIFT_IR_STATE: self.nstate = ( JTAGStates.EXIT1_IR_STATE if get_int(self.tms) == 1 else JTAGStates.SHIFT_IR_STATE ) elif self.state == JTAGStates.EXIT1_IR_STATE: self.nstate = ( JTAGStates.UPDATE_IR_STATE if get_int(self.tms) == 1 else JTAGStates.PAUSE_IR_STATE ) elif self.state == JTAGStates.PAUSE_IR_STATE: self.nstate = ( JTAGStates.EXIT2_IR_STATE if get_int(self.tms) == 1 else JTAGStates.PAUSE_IR_STATE ) elif self.state == JTAGStates.EXIT2_IR_STATE: self.nstate = ( JTAGStates.UPDATE_IR_STATE if get_int(self.tms) == 1 else JTAGStates.SHIFT_IR_STATE ) elif self.state == JTAGStates.UPDATE_IR_STATE: self.nstate = ( JTAGStates.SELECT_DR_SCAN_STATE if get_int(self.tms) == 1 else JTAGStates.RUN_TEST_IDLE_STATE ) else: self.nstate = JTAGStates.TEST_LOGIC_RESET_STATE if self.prev_nstate != self.nstate: self.logger.debug( "Switching nstate {} to {}".format( JTAGStates(self.prev_nstate).name, JTAGStates(self.nstate).name, ) ) def predict_regs_posedge(self): """ Calculate values of internal registers IR, DR and SR """ self.dr = self.ndr if self.trst_n == 0: self.sr = LogicArray(0, self.reg_range) else: self.sr = LogicArray(get_int(self.nsr), self.reg_range) if self.trst_n == 0: self.nsr = LogicArray(0, self.nsr.range) self.ir = LogicArray(1, self.ir.range) self.ndr = LogicArray(0, self.dr.range) if self.state == JTAGStates.UPDATE_IR_STATE: self.ir = ( LogicArray(0x1F, self.ir.range) if (self.sr[4:0].integer == 0) else self.sr[4:0] ) if self.state == JTAGStates.UPDATE_DR_STATE and self.ir == JTAGInstructions.DR_EN_1: self.ndr = LogicArray(get_int(self.sr), self.reg_range) else: self.ndr = concat(self.dr[self.AWIDTH + 33 : 2], LogicArray(0, range(2))) self.predict_nsr_reg() def predict_nsr_reg(self): """ Calculate next value of the SR register """ tdi_lr = LogicArray(get_int(self.tdi)) self.nsr = LogicArray(get_int(self.sr), self.reg_range) # Predict value of nsr register if self.state == JTAGStates.SHIFT_DR_STATE: if self.ir == JTAGInstructions.DR_EN_1: self.nsr = concat(tdi_lr, self.sr[self.AWIDTH + 33 : 1]) elif self.ir in [JTAGInstructions.DR_EN_0, JTAGInstructions.DEVICE_ID_SEL]: self.nsr = concat( LogicArray(0, range(self.AWIDTH + 2)), concat(tdi_lr, self.sr[31:1]) ) else: self.nsr = LogicArray(get_int(self.tdi), self.nsr.range) elif self.state == JTAGStates.CAPTURE_DR_STATE: self.nsr[0] = 0 if self.ir == JTAGInstructions.DR_EN_0: self.nsr = concat( LogicArray(0, range(self.AWIDTH + 19)), concat( concat(concat(JTAGDefaults.IDLE, JTAGDefaults.DMI_STAT), Defaults.ABITS), JTAGDefaults.VERSION, ), ) elif self.ir == JTAGInstructions.DR_EN_1: self.nsr = concat( concat( LogicArray(0, range(self.AWIDTH)), LogicArray(self.rd_data.value, Range(31, "downto", 0)), ), JTAGDefaults.RD_STATUS, ) elif self.ir == JTAGInstructions.DEVICE_ID_SEL: self.nsr = concat( LogicArray(0, range(self.AWIDTH + 2)), concat(Defaults.JTAG_ID, LogicArray(1)) ) elif self.state == JTAGStates.SHIFT_IR_STATE: self.nsr = concat(LogicArray(0, range(self.AWIDTH + 29)), concat(tdi_lr, self.sr[4:1])) elif self.state == JTAGStates.CAPTURE_IR_STATE: self.nsr = LogicArray(1, self.reg_range) def predict_regs_negedge(self): self.tdo = Logic(get_int(self.sr[0])) self.tdoEnable = ( Logic(1) if self.state in [JTAGStates.SHIFT_DR_STATE, JTAGStates.SHIFT_IR_STATE] else Logic(0) ) self.predict_nsr_reg() def predict_ports(self): """ Calculate JTAG TAP output ports' values """ self.tdoEnable = ( Logic(1) if self.state in [JTAGStates.SHIFT_DR_STATE, JTAGStates.SHIFT_IR_STATE] else Logic(0) ) self.wr_addr = LogicArray(get_int(self.dr[self.AWIDTH + 34 - 1 : 34])) self.wr_data = LogicArray(get_int(self.dr[33:2])) self.wr_en = Logic(get_int(self.dr[1])) self.rd_en = Logic(get_int(self.dr[0])) if self.trst_n == 0: self.dmi_hard_reset = Logic(0) if self.state == JTAGStates.UPDATE_DR_STATE and self.ir == JTAGInstructions.DR_EN_0: self.dmi_hard_reset = Logic(get_int(self.sr[17])) else: self.dmi_hard_reset = Logic(0) def predict_jtag_outputs(self, edge): """ Predict JTAG TAP internal state and outputs based on current inputs. This method is assumed to be executed just after detecting an edge of the clock. Since it must know previous state of the FSM, prediction should be executed after each clock edge. """ assert edge in ["pos", "neg"] self.update_nstate() if edge == "pos": self.update_state() self.predict_regs_posedge() else: self.predict_regs_negedge() self.predict_ports() self.logger.debug(str(self)) self.logger.debug("Internal registers:") self.logger.debug("nsr: {}".format(self.nsr)) self.logger.debug("sr: {}".format(self.sr)) self.logger.debug("dr: {}".format(self.dr)) self.logger.debug("ir: {}\n".format(self.ir)) ================================================ FILE: verification/block/dmi/jtag_seq.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: BSD-2-Clause from pyuvm import * from common import BaseSeq class JTAGBaseSeqItem(uvm_sequence_item): def __init__(self, name, tms=1, tdi=0): super().__init__(name) self.name = name self.tms = tms self.tdi = tdi def __str__(self): return self.__class__.__name__ def randomize(self): pass class SetIRSequence(BaseSeq): def __init__(self, name, instruction): super().__init__(name) self.instr = instruction async def body(self): items = [ JTAGBaseSeqItem("switch_to_select_dr_scan", 1, 0), JTAGBaseSeqItem("switch_to_select_ir_scan", 1, 0), JTAGBaseSeqItem("switch_to_capture_ir", 0, 0), JTAGBaseSeqItem("switch_to_shift_ir", 0, 0), JTAGBaseSeqItem("shift_ir_bit_0", 0, (self.instr >> 0) & 0x1), JTAGBaseSeqItem("shift_ir_bit_1", 0, (self.instr >> 1) & 0x1), JTAGBaseSeqItem("shift_ir_bit_2", 0, (self.instr >> 2) & 0x1), JTAGBaseSeqItem("shift_ir_bit_3", 0, (self.instr >> 3) & 0x1), JTAGBaseSeqItem("switch_to_exit1_ir", 1, (self.instr >> 4) & 0x1), JTAGBaseSeqItem("switch_to_update_ir", 1, 0), JTAGBaseSeqItem("switch_to_idle", 0, 0), JTAGBaseSeqItem("idle0", 0, 0), JTAGBaseSeqItem("idle1", 0, 0), ] await self.run_items(items) class ReadIDCODESequence(SetIRSequence): def __init__(self, name): super().__init__(name, 0b00001) class CaptureDRSequence(BaseSeq): def __init__(self, name): super().__init__(name) async def body(self): shift_dr_items = [] for i in range(40): shift_dr_items.append(JTAGBaseSeqItem("shift_dr_bit{}".format(i), 0, 0)) items = [ JTAGBaseSeqItem("switch_to_select_dr_scan", 1, 0), JTAGBaseSeqItem("switch_to_capture_dr", 0, 0), JTAGBaseSeqItem("switch_to_shift_dr", 0, 0), ] items += shift_dr_items items += [ JTAGBaseSeqItem("switch_to_exit1_dr", 1, 0), JTAGBaseSeqItem("switch_to_update_dr", 1, 0), JTAGBaseSeqItem("switch_to_idle", 0, 0), JTAGBaseSeqItem("idle0", 0, 0), JTAGBaseSeqItem("idle1", 0, 0), ] await self.run_items(items) ================================================ FILE: verification/block/dmi/test_dmi_read_write.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from dmi_seq import * from jtag_seq import * from testbench import BaseTest @pyuvm.test() class TestDMIReadRegs(BaseTest): def end_of_elaboration_phase(self): self.seqr = ConfigDB().get(None, "", "JTAG_SEQR") self.set_ir_dren0_seq = SetIRSequence("set_ir_seq", 0b10000) self.set_ir_dren1_seq = SetIRSequence("set_ir_seq", 0b10001) self.read_dmcontrol_seq = AccessDMIRegSequence("read_dmcontrol_seq", addr=0x10) self.read_dmstatus_seq = AccessDMIRegSequence("read_dmstatus_seq", addr=0x11) async def run(self): await self.set_ir_dren0_seq.start(self.seqr) await self.read_dmcontrol_seq.start(self.seqr) await self.set_ir_dren1_seq.start(self.seqr) await self.read_dmstatus_seq.start(self.seqr) @pyuvm.test() class TestDMIWriteRegs(BaseTest): def end_of_elaboration_phase(self): self.seqr = ConfigDB().get(None, "", "JTAG_SEQR") self.set_ir_dren1_seq = SetIRSequence("set_ir_seq", 0b10001) self.write_dmcontrol_seq = AccessDMIRegSequence( "write_dmcontrol_seq", addr=0x10, data=0x01234567, is_write=True ) self.write_dmstatus_seq = AccessDMIRegSequence( "write_dmstatus_seq", addr=0x11, data=0xDEADBEEF, is_write=True ) async def run(self): await self.set_ir_dren1_seq.start(self.seqr) await self.write_dmcontrol_seq.start(self.seqr) await self.write_dmstatus_seq.start(self.seqr) @pyuvm.test() class TestDMIReadWriteRegs(BaseTest): def end_of_elaboration_phase(self): self.seqr = ConfigDB().get(None, "", "JTAG_SEQR") self.set_ir_dren1_seq = SetIRSequence("set_ir_seq", 0b10001) self.write_dmcontrol_seq = AccessDMIRegSequence( "write_dmcontrol_seq", addr=0x10, data=0x01234567, is_write=True ) self.write_dmstatus_seq = AccessDMIRegSequence( "write_dmstatus_seq", addr=0x11, data=0xDEADBEEF, is_write=True ) self.read_dmcontrol_seq = AccessDMIRegSequence("read_dmcontrol_seq", addr=0x10) self.read_dmstatus_seq = AccessDMIRegSequence("read_dmstatus_seq", addr=0x11) async def run(self): await self.set_ir_dren1_seq.start(self.seqr) await self.write_dmcontrol_seq.start(self.seqr) await self.write_dmstatus_seq.start(self.seqr) await self.read_dmcontrol_seq.start(self.seqr) await self.read_dmstatus_seq.start(self.seqr) @pyuvm.test() class TestUncoreDMIReadWriteRegs(BaseTest): def end_of_elaboration_phase(self): self.jtag_seqr = ConfigDB().get(None, "", "JTAG_SEQR") self.dmi_seqr = ConfigDB().get(None, "", "DMI_SEQR") self.uncore_enable_seq = SetUncoreEnableSequence("uncore_enable_seq", 1) self.set_ir_dren1_seq = SetIRSequence("set_ir_seq", 0b10001) self.write_core_seq1 = AccessDMIRegSequence( "write_core_seq1", addr=0x11, data=0xDEADBEEF, is_write=True ) self.write_uncore_seq1 = AccessDMIRegSequence( "write_uncore_seq1", addr=0x7F, data=0x76543210, is_write=True ) self.read_core_seq1 = AccessDMIRegSequence("read_core_seq1", addr=0x11) self.read_uncore_seq1 = AccessDMIRegSequence("read_uncore_seq1", addr=0x7F) self.write_core_seq2 = AccessDMIRegSequence( "write_core_seq2", addr=0x4F, data=0xBEEFDEAD, is_write=True ) self.write_uncore_seq2 = AccessDMIRegSequence( "write_uncore_seq2", addr=0x50, data=0xFEEDABED, is_write=True ) self.read_core_seq2 = AccessDMIRegSequence("read_core_seq2", addr=0x4F) self.read_uncore_seq2 = AccessDMIRegSequence("read_uncore_seq2", addr=0x50) async def run(self): await self.uncore_enable_seq.start(self.dmi_seqr) await self.set_ir_dren1_seq.start(self.jtag_seqr) await self.write_core_seq1.start(self.jtag_seqr) await self.write_uncore_seq1.start(self.jtag_seqr) await self.read_core_seq1.start(self.jtag_seqr) await self.read_uncore_seq1.start(self.jtag_seqr) await self.write_core_seq2.start(self.jtag_seqr) await self.write_uncore_seq2.start(self.jtag_seqr) await self.read_core_seq2.start(self.jtag_seqr) await self.read_uncore_seq2.start(self.jtag_seqr) ================================================ FILE: verification/block/dmi/test_dmi_tap_fsm.py ================================================ import cocotb from cocotb.clock import Clock from cocotb.triggers import RisingEdge, Timer # TAP State Constants (renamed to *_STATE format) TEST_LOGIC_RESET_STATE = 0x0 RUN_TEST_IDLE_STATE = 0x1 SELECT_DR_SCAN_STATE = 0x2 CAPTURE_DR_STATE = 0x3 SHIFT_DR_STATE = 0x4 EXIT1_DR_STATE = 0x5 PAUSE_DR_STATE = 0x6 EXIT2_DR_STATE = 0x7 UPDATE_DR_STATE = 0x8 SELECT_IR_SCAN_STATE = 0x9 CAPTURE_IR_STATE = 0xA SHIFT_IR_STATE = 0xB EXIT1_IR_STATE = 0xC PAUSE_IR_STATE = 0xD EXIT2_IR_STATE = 0xE UPDATE_IR_STATE = 0xF # Define the TAP state transition table TAP_TRANSITIONS = { (TEST_LOGIC_RESET_STATE, TEST_LOGIC_RESET_STATE): 1, (TEST_LOGIC_RESET_STATE, RUN_TEST_IDLE_STATE): 0, (RUN_TEST_IDLE_STATE, SELECT_DR_SCAN_STATE): 1, (RUN_TEST_IDLE_STATE, RUN_TEST_IDLE_STATE): 0, (SELECT_DR_SCAN_STATE, SELECT_IR_SCAN_STATE): 1, (SELECT_DR_SCAN_STATE, CAPTURE_DR_STATE): 0, (CAPTURE_DR_STATE, EXIT1_DR_STATE): 1, (CAPTURE_DR_STATE, SHIFT_DR_STATE): 0, (SHIFT_DR_STATE, EXIT1_DR_STATE): 1, (SHIFT_DR_STATE, SHIFT_DR_STATE): 0, (EXIT1_DR_STATE, UPDATE_DR_STATE): 1, (EXIT1_DR_STATE, PAUSE_DR_STATE): 0, (PAUSE_DR_STATE, EXIT2_DR_STATE): 1, (PAUSE_DR_STATE, PAUSE_DR_STATE): 0, (EXIT2_DR_STATE, UPDATE_DR_STATE): 1, (EXIT2_DR_STATE, SHIFT_DR_STATE): 0, (UPDATE_DR_STATE, SELECT_DR_SCAN_STATE): 1, (UPDATE_DR_STATE, RUN_TEST_IDLE_STATE): 0, (SELECT_IR_SCAN_STATE, TEST_LOGIC_RESET_STATE): 1, (SELECT_IR_SCAN_STATE, CAPTURE_IR_STATE): 0, (CAPTURE_IR_STATE, EXIT1_IR_STATE): 1, (CAPTURE_IR_STATE, SHIFT_IR_STATE): 0, (SHIFT_IR_STATE, EXIT1_IR_STATE): 1, (SHIFT_IR_STATE, SHIFT_IR_STATE): 0, (EXIT1_IR_STATE, UPDATE_IR_STATE): 1, (EXIT1_IR_STATE, PAUSE_IR_STATE): 0, (PAUSE_IR_STATE, EXIT2_IR_STATE): 1, (PAUSE_IR_STATE, PAUSE_IR_STATE): 0, (EXIT2_IR_STATE, UPDATE_IR_STATE): 1, (EXIT2_IR_STATE, SHIFT_IR_STATE): 0, (UPDATE_IR_STATE, SELECT_DR_SCAN_STATE): 1, (UPDATE_IR_STATE, RUN_TEST_IDLE_STATE): 0, } # Traverse each possible transition TEST_PATH = [ TEST_LOGIC_RESET_STATE, TEST_LOGIC_RESET_STATE, RUN_TEST_IDLE_STATE, RUN_TEST_IDLE_STATE, SELECT_DR_SCAN_STATE, CAPTURE_DR_STATE, SHIFT_DR_STATE, SHIFT_DR_STATE, EXIT1_DR_STATE, PAUSE_DR_STATE, PAUSE_DR_STATE, EXIT2_DR_STATE, UPDATE_DR_STATE, SELECT_DR_SCAN_STATE, CAPTURE_DR_STATE, EXIT1_DR_STATE, PAUSE_DR_STATE, EXIT2_DR_STATE, UPDATE_DR_STATE, RUN_TEST_IDLE_STATE, SELECT_DR_SCAN_STATE, CAPTURE_DR_STATE, EXIT1_DR_STATE, PAUSE_DR_STATE, EXIT2_DR_STATE, SHIFT_DR_STATE, EXIT1_DR_STATE, UPDATE_DR_STATE, RUN_TEST_IDLE_STATE, SELECT_DR_SCAN_STATE, SELECT_IR_SCAN_STATE, CAPTURE_IR_STATE, SHIFT_IR_STATE, SHIFT_IR_STATE, EXIT1_IR_STATE, PAUSE_IR_STATE, PAUSE_IR_STATE, EXIT2_IR_STATE, SHIFT_IR_STATE, EXIT1_IR_STATE, PAUSE_IR_STATE, EXIT2_IR_STATE, UPDATE_IR_STATE, SELECT_DR_SCAN_STATE, SELECT_IR_SCAN_STATE, TEST_LOGIC_RESET_STATE, RUN_TEST_IDLE_STATE, SELECT_DR_SCAN_STATE, SELECT_IR_SCAN_STATE, CAPTURE_IR_STATE, EXIT1_IR_STATE, UPDATE_IR_STATE, ] @cocotb.test() async def test_full_tap_fsm(dut): """Exercise all possible TAP FSM states via TMS and TCK.""" cocotb.start_soon(Clock(dut.tck, 3, units="ns").start()) cocotb.start_soon(Clock(dut.core_clk, 1, units="ns").start()) # Assert tms to ensure entering the test with `TEST_LOGIC_RESET_STATE` dut.tms.value = 1 # Apply reset (active-low) dut.trst_n.value = 0 await Timer(20, units="ns") dut.trst_n.value = 1 await RisingEdge(dut.tck) # Ensure FSM starts in Test-Logic-Reset assert ( dut.wrapper.i_jtag_tap.state.value == TEST_LOGIC_RESET_STATE ), f"Expected state TEST_LOGIC_RESET_STATE, got {dut.wrapper.i_jtag_tap.state.value}" assert ( dut.wrapper.i_jtag_tap.state.value == TEST_LOGIC_RESET_STATE ), f"Expected state TEST_LOGIC_RESET_STATE after reset, got {dut.wrapper.i_jtag_tap.state.value}" # Iterate through all valid state transitions for i in range(len(TEST_PATH) - 1): s0, s1 = TEST_PATH[i], TEST_PATH[i + 1] tms_value = TAP_TRANSITIONS[(s0, s1)] # Apply TMS value dut.tms.value = tms_value await RisingEdge(dut.tck) assert ( dut.wrapper.i_jtag_tap.state.value == s0 and dut.wrapper.i_jtag_tap.nstate.value == s1 ), f"Expected state {s0}, got {dut.wrapper.i_jtag_tap.state.value}" # Apply reset (active-low) dut.trst_n.value = 0 await RisingEdge(dut.tck) assert ( dut.wrapper.i_jtag_tap.state.value == TEST_LOGIC_RESET_STATE ), f"Expected state TEST_LOGIC_RESET_STATE after reset, got {dut.wrapper.i_jtag_tap.state.value}" ================================================ FILE: verification/block/dmi/test_jtag_ir.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from jtag_pkg import JTAGInstructions from jtag_seq import * from testbench import BaseTest @pyuvm.test() class TestJTAGSetIR(BaseTest): def end_of_elaboration_phase(self): self.seqr = ConfigDB().get(None, "", "JTAG_SEQR") self.set_ir_seq = SetIRSequence("set_ir_seq", JTAGInstructions.DEVICE_ID_SEL.integer) async def run(self): await self.set_ir_seq.start(self.seqr) @pyuvm.test() class TestJTAGReadIDCODE(BaseTest): def end_of_elaboration_phase(self): self.seqr = ConfigDB().get(None, "", "JTAG_SEQR") self.read_idcode_seq = CaptureDRSequence("read_idcode_seq") async def run(self): await self.read_idcode_seq.start(self.seqr) @pyuvm.test() class TestJTAGSetIRReadDR(BaseTest): def end_of_elaboration_phase(self): self.seqr = ConfigDB().get(None, "", "JTAG_SEQR") self.set_ir_seq = SetIRSequence("set_ir_seq", JTAGInstructions.DEVICE_ID_SEL.integer) self.read_idcode_seq = CaptureDRSequence("read_idcode_seq") async def run(self): await self.set_ir_seq.start(self.seqr) await self.read_idcode_seq.start(self.seqr) ================================================ FILE: verification/block/dmi/testbench.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import os from decimal import Decimal import pyuvm from cocotb.clock import Clock from cocotb.triggers import ClockCycles, Timer from dmi_agent import DMIAgent from jtag_agent import JTAGAgent from jtag_predictor import JTAGPredictor from pyuvm import * class Scoreboard(uvm_scoreboard): def build_phase(self): self.jtag_rsp_fifo = uvm_tlm_analysis_fifo("jtag_rsp_fifo", self) self.jtag_rsp_get_port = uvm_get_port("jtag_rsp_get_port", self) self.jtag_rsp_export = self.jtag_rsp_fifo.analysis_export self.dmi_rsp_fifo = uvm_tlm_analysis_fifo("dmi_rsp_fifo", self) self.dmi_rsp_get_port = uvm_get_port("dmi_rsp_get_port", self) self.dmi_rsp_export = self.dmi_rsp_fifo.analysis_export def connect_phase(self): self.jtag_rsp_get_port.connect(self.jtag_rsp_fifo.get_export) self.dmi_rsp_get_port.connect(self.dmi_rsp_fifo.get_export) def check_phase(self): self.logger.debug("Entering Scoreboard check phase") self.check_jtag() self.check_dmi() def check_dmi(self): passed = True while self.dmi_rsp_get_port.can_get(): _, item = self.dmi_rsp_get_port.try_get() values, dmi_type = item rd_data, dmi_rdata, dmi_addr, dmi_en, pred_en = values if pred_en != dmi_en: self.logger.error("Unexpected state of DMI enable signal") passed = False self.logger.debug("Checking DMI {} at address {}".format(dmi_type, str(hex(dmi_addr)))) if dmi_en and (rd_data != dmi_rdata): self.logger.error( "Read data does not match expected data ({} vs {})".format( str(hex(rd_data)), str(hex(dmi_rdata)) ) ) passed = False assert passed def check_jtag(self): passed = True while self.jtag_rsp_get_port.can_get(): _, item = self.jtag_rsp_get_port.try_get() out_ports = item[0] predicted_ports = item[1] for i, s in enumerate(["tdo", "tdoEnable"]): out = out_ports[i] predicted = predicted_ports[i] self.logger.debug( "Current check of {} (actual: {} vs expected: {})".format(s, out, predicted) ) if out != predicted: self.logger.error("Unexpected state of {} ({} vs {})".format(s, out, predicted)) passed = False assert passed class BaseEnvironment(uvm_env): def __init__(self, name, test_obj): super().__init__(name, test_obj) def build_phase(self): # Config # JTAG clock must be at least twice as fast as core clock ConfigDB().set(None, "*", "TEST_JTAG_CLK_PERIOD", 3) ConfigDB().set(None, "*", "TEST_CORE_CLK_PERIOD", 1) ConfigDB().set(None, "*", "AWIDTH", 7) self.jtag_agent = JTAGAgent("jtag_agent", self) self.dmi_agent = DMIAgent("dmi_agent", self) self.predictor = JTAGPredictor(cocotb.top) self.scoreboard = Scoreboard("scoreboard", self) ConfigDB().set(None, "*", "JTAG_PREDICTOR", self.predictor) def connect_phase(self): self.jtag_agent.monitor.ap.connect(self.scoreboard.jtag_rsp_export) self.dmi_agent.monitor.ap.connect(self.scoreboard.dmi_rsp_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent): super().__init__(name, parent) # Synchronize pyuvm logging level with cocotb logging level. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = BaseEnvironment("env", self) def start_clock(self, name, period): sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self, signals, timeLength="100e-9", isActiveHigh=True): assert isinstance(signals, list) for s in signals: signal = getattr(cocotb.top, s) signal.value = int(isActiveHigh) await Timer(Decimal(timeLength), units="sec") for s in signals: signal = getattr(cocotb.top, s) signal.value = not int(isActiveHigh) async def run_phase(self): self.raise_objection() # Start clocks core_period = ConfigDB().get(None, "", "TEST_CORE_CLK_PERIOD") jtag_period = ConfigDB().get(None, "", "TEST_JTAG_CLK_PERIOD") self.start_clock("core_clk", core_period) self.start_clock("tck", jtag_period) clk = getattr(cocotb.top, "core_clk") # Issue reset resetLength = "100e-9" await self.do_reset( signals=["trst_n", "core_rst_n"], timeLength=resetLength, isActiveHigh=False ) await ClockCycles(clk, 2) await self.run() await ClockCycles(clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/exu_alu/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_exu_alu_ctl_wrapper VERILOG_SOURCES = \ $(TEST_DIR)/el2_exu_alu_ctl_wrapper.sv \ $(SRCDIR)/exu/el2_exu_alu_ctl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/exu_alu/config.vlt ================================================ `verilator_config lint_off -rule WIDTHTRUNC -file "*/el2_exu_alu_ctl_wrapper.sv" lint_off -rule UNUSEDPARAM -file "*/el2_exu_alu_ctl_wrapper.sv" ================================================ FILE: verification/block/exu_alu/el2_exu_alu_ctl_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_exu_alu_ctl_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic scan_mode, input logic flush_upper_x, input logic flush_lower_r, input logic enable, input logic valid_in, // Unpacked el2_alu_pkt_t input logic ap_clz, input logic ap_ctz, input logic ap_cpop, input logic ap_sext_b, input logic ap_sext_h, input logic ap_min, input logic ap_max, input logic ap_pack, input logic ap_packu, input logic ap_packh, input logic ap_rol, input logic ap_ror, input logic ap_grev, input logic ap_gorc, input logic ap_zbb, input logic ap_bset, input logic ap_bclr, input logic ap_binv, input logic ap_bext, input logic ap_sh1add, input logic ap_sh2add, input logic ap_sh3add, input logic ap_zba, input logic ap_land, input logic ap_lor, input logic ap_lxor, input logic ap_sll, input logic ap_srl, input logic ap_sra, input logic ap_beq, input logic ap_bne, input logic ap_blt, input logic ap_bge, input logic ap_add, input logic ap_sub, input logic ap_slt, input logic ap_unsignl, input logic ap_jall, input logic ap_predict_tl, input logic ap_predict_nt, input logic ap_csr_write, input logic ap_csr_imm, input logic csr_ren_in, input logic [31:0] csr_rddata_in, input logic signed [31:0] a_in, input logic [31:0] b_in, input logic [31:1] pc_in, input el2_predict_pkt_t pp_in, input logic [12:1] brimm_in, output logic [31:0] result_ff, output logic flush_upper_out, output logic flush_final_out, output logic [31:1] flush_path_out, output logic [31:1] pc_ff, output logic pred_correct_out, output el2_predict_pkt_t predict_p_out ); // Pack ap el2_alu_pkt_t ap; assign ap.clz = ap_clz; assign ap.ctz = ap_ctz; assign ap.cpop = ap_cpop; assign ap.sext_b = ap_sext_b; assign ap.sext_h = ap_sext_h; assign ap.min = ap_min; assign ap.max = ap_max; assign ap.pack = ap_pack; assign ap.packu = ap_packu; assign ap.packh = ap_packh; assign ap.rol = ap_rol; assign ap.ror = ap_ror; assign ap.grev = ap_grev; assign ap.gorc = ap_gorc; assign ap.zbb = ap_zbb; assign ap.bset = ap_bset; assign ap.bclr = ap_bclr; assign ap.binv = ap_binv; assign ap.bext = ap_bext; assign ap.sh1add = ap_sh1add; assign ap.sh2add = ap_sh2add; assign ap.sh3add = ap_sh3add; assign ap.zba = ap_zba; assign ap.land = ap_land; assign ap.lor = ap_lor; assign ap.lxor = ap_lxor; assign ap.sll = ap_sll; assign ap.srl = ap_srl; assign ap.sra = ap_sra; assign ap.beq = ap_beq; assign ap.bne = ap_bne; assign ap.blt = ap_blt; assign ap.bge = ap_bge; assign ap.add = ap_add; assign ap.sub = ap_sub; assign ap.slt = ap_slt; assign ap.unsign = ap_unsignl; assign ap.jal = ap_jall; assign ap.predict_t = ap_predict_tl; assign ap.predict_nt = ap_predict_nt; assign ap.csr_write = ap_csr_write; assign ap.csr_imm = ap_csr_imm; // EXU ALU el2_exu_alu_ctl alu (.*); endmodule ================================================ FILE: verification/block/exu_alu/test_arith.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseSequence, BaseTest # ============================================================================= @pyuvm.test() class TestAdd(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["add"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestSub(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["sub"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestAll(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["add", "sub"]) async def run(self): await self.seq.start(self.env.alu_seqr) ================================================ FILE: verification/block/exu_alu/test_logic.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseSequence, BaseTest # ============================================================================= @pyuvm.test() class TestAnd(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["and"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestOr(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["or"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestXor(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["xor"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestAll(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["and", "or", "xor"]) async def run(self): await self.seq.start(self.env.alu_seqr) ================================================ FILE: verification/block/exu_alu/test_zba.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseSequence, BaseTest # ============================================================================= @pyuvm.test() class TestSh1add(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["sh1add"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestSh2add(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["sh2add"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestSh3add(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["sh3add"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestAll(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["sh1add", "sh2add", "sh3add"]) async def run(self): await self.seq.start(self.env.alu_seqr) ================================================ FILE: verification/block/exu_alu/test_zbb.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseSequence, BaseTest # ============================================================================= @pyuvm.test() class TestClz(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["clz"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestCtz(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["ctz"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestCpop(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["cpop"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestSextb(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["sext_b"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestSexth(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["sext_h"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestRol(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["rol"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestRor(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["ror"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestAll(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence( "stimulus", ["clz", "ctz", "cpop", "sext_b", "sext_h", "rol", "ror"] ) async def run(self): await self.seq.start(self.env.alu_seqr) ================================================ FILE: verification/block/exu_alu/test_zbp.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseSequence, BaseTest # ============================================================================= @pyuvm.test() class TestPack(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["pack"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestPackh(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["packh"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestAll(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["pack", "packh"]) async def run(self): await self.seq.start(self.env.alu_seqr) ================================================ FILE: verification/block/exu_alu/test_zbs.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseSequence, BaseTest # ============================================================================= @pyuvm.test() class TestBset(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["bset"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestBclr(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["bclr"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestBinv(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["binv"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestBext(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["bext"]) async def run(self): await self.seq.start(self.env.alu_seqr) @pyuvm.test() class TestAll(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["bset", "bclr", "binv", "bext"]) async def run(self): await self.seq.start(self.env.alu_seqr) ================================================ FILE: verification/block/exu_alu/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import math import os import random import struct import pyuvm from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from pyuvm import * # ============================================================================== class AluInputItem(uvm_sequence_item): """ ALU input data """ def __init__(self, op, a, b, csr=0, pc=0): super().__init__("AluInputItem") self.op = op self.a = a self.b = b self.csr = csr self.pc = pc class AluOutputItem(uvm_sequence_item): """ ALU output data """ def __init__(self, out): super().__init__("AluOutputItem") self.out = out # ============================================================================== class AluDriver(uvm_driver): """ ALU input driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, AluInputItem): # Wait for rising edge await RisingEdge(self.dut.clk) self.dut.valid_in.value = 1 # Zbb self.dut.ap_clz.value = it.op in ["clz"] self.dut.ap_ctz.value = it.op in ["ctz"] self.dut.ap_cpop.value = it.op in ["cpop"] self.dut.ap_sext_b.value = it.op in ["sext_b"] self.dut.ap_sext_h.value = it.op in ["sext_h"] self.dut.ap_rol.value = it.op in ["rol"] self.dut.ap_ror.value = it.op in ["ror"] # Zbs self.dut.ap_bset.value = it.op in ["bset"] self.dut.ap_bclr.value = it.op in ["bclr"] self.dut.ap_binv.value = it.op in ["binv"] self.dut.ap_bext.value = it.op in ["bext"] # Zbp self.dut.ap_pack.value = it.op in ["pack"] self.dut.ap_packh.value = it.op in ["packh"] # Zba self.dut.ap_sh1add.value = it.op in ["sh1add"] self.dut.ap_sh2add.value = it.op in ["sh2add"] self.dut.ap_sh3add.value = it.op in ["sh3add"] # ap_zba has to be set to 1 to use sh??add instructions self.dut.ap_zba.value = it.op in ["sh1add", "sh2add", "sh3add"] # Arith self.dut.ap_add.value = it.op in ["add"] self.dut.ap_sub.value = it.op in ["sub"] self.dut.ap_land.value = it.op in ["and"] self.dut.ap_lor.value = it.op in ["or"] self.dut.ap_lxor.value = it.op in ["xor"] # Operands self.dut.a_in.value = it.a self.dut.b_in.value = it.b self.dut.csr_rddata_in.value = it.csr self.dut.pc_in.value = it.pc # Deassert valid after one cycle await RisingEdge(self.dut.clk) self.dut.valid_in.value = 0 else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class AluInputMonitor(uvm_component): """ Monitor for ALU inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Act on rising edges await RisingEdge(self.dut.clk) # We got a valid input if self.dut.valid_in.value: # Sample control signals and operands a = int(self.dut.a_in.value) b = int(self.dut.b_in.value) # Decode operation op = None if int(self.dut.ap_add.value): op = "add" elif int(self.dut.ap_sub.value): op = "sub" elif int(self.dut.ap_land.value): op = "and" elif int(self.dut.ap_lor.value): op = "or" elif int(self.dut.ap_lxor.value): op = "xor" elif int(self.dut.ap_clz.value): op = "clz" elif int(self.dut.ap_ctz.value): op = "ctz" elif int(self.dut.ap_cpop.value): op = "cpop" elif int(self.dut.ap_sext_b.value): op = "sext_b" elif int(self.dut.ap_sext_h.value): op = "sext_h" elif int(self.dut.ap_rol.value): op = "rol" elif int(self.dut.ap_ror.value): op = "ror" elif int(self.dut.ap_bset.value): op = "bset" elif int(self.dut.ap_bclr.value): op = "bclr" elif int(self.dut.ap_binv.value): op = "binv" elif int(self.dut.ap_bext.value): op = "bext" elif int(self.dut.ap_pack.value): op = "pack" elif int(self.dut.ap_packh.value): op = "packh" elif int(self.dut.ap_sh1add.value): op = "sh1add" elif int(self.dut.ap_sh2add.value): op = "sh2add" elif int(self.dut.ap_sh3add.value): op = "sh3add" # Write item self.ap.write( AluInputItem( op=op, a=a, b=b, ) ) class AluOutputMonitor(uvm_component): """ Monitor for ALU outputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Act on rising edges await RisingEdge(self.dut.clk) # We got a valid input if self.dut.valid_in.value: # Wait 1 cycle await RisingEdge(self.dut.clk) # Sample result & write the item result = int(self.dut.result_ff.value) self.ap.write(AluOutputItem(out=result)) # ============================================================================== class AluScoreboard(uvm_component): """ Generic ALU scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True # Predict result result = None INT_MASK = 0xFFFFFFFF if item_inp.op == "add": result = (item_inp.a + item_inp.b) & INT_MASK elif item_inp.op == "sub": result = (item_inp.a - item_inp.b) & INT_MASK elif item_inp.op == "and": result = item_inp.a & item_inp.b elif item_inp.op == "or": result = item_inp.a | item_inp.b elif item_inp.op == "xor": result = item_inp.a ^ item_inp.b elif item_inp.op == "clz": result = next((i for i in range(32) if ((item_inp.a << i) & INT_MASK) >> 31), 32) elif item_inp.op == "ctz": result = next((i for i in range(32) if (item_inp.a >> i) & 1), 32) elif item_inp.op == "cpop": result = bin(item_inp.a).count("1") elif item_inp.op == "sext_b": last_byte = item_inp.a & 0xFF sign = (item_inp.a & 0x00000080) >> 7 result = (0xFFFFFF00 * sign) | last_byte elif item_inp.op == "sext_h": last_2_bytes = item_inp.a & 0xFFFF sign = (item_inp.a & 0x00008000) >> 15 result = (0xFFFF0000 * sign) | last_2_bytes elif item_inp.op == "rol": shamt = item_inp.b & 31 result = (item_inp.a << shamt) & INT_MASK | (item_inp.a >> ((32 - shamt) & 31)) elif item_inp.op == "ror": shamt = item_inp.b & 31 result = (item_inp.a >> shamt) | (item_inp.a << ((32 - shamt) & 31)) & INT_MASK elif item_inp.op == "bset": result = item_inp.a | (1 << (item_inp.b & 31)) elif item_inp.op == "bclr": result = item_inp.a & ~(1 << (item_inp.b & 31)) elif item_inp.op == "binv": result = item_inp.a ^ (1 << (item_inp.b & 31)) elif item_inp.op == "bext": result = 1 & (item_inp.a >> (item_inp.b & 31)) elif item_inp.op == "pack": result = (((item_inp.a << 16) & INT_MASK) >> 16) | (item_inp.b << 16) & INT_MASK elif item_inp.op == "packh": result = (item_inp.a & 0xFF) | ((item_inp.b & 0xFF) << 8) elif item_inp.op in ["sh1add", "sh2add", "sh3add"]: shift = int(item_inp.op[2]) result = ((item_inp.a << shift) + item_inp.b) & INT_MASK else: self.logger.error("Unknown ALU operation '{}'".format(item_inp.op)) self.passed = False self.logger.debug( "{} {} {} == {}".format( item_inp.a, item_inp.op, item_inp.b, item_out.out, ) ) # Check result assert result is not None if item_out.out != result: self.logger.error( "{} {} {} != {} (should be {})".format( item_inp.a, item_inp.op, item_inp.b, item_out.out, result ) ) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseSequence(uvm_sequence): """ Base sequence of randomized 32-bit A and B operands along with operators picked randomly from the allowed set """ def __init__(self, name, ops=None): super().__init__(name) if ops is None: self.ops = ["add", "sub"] else: self.ops = ops async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") for i in range(count): a = random.randrange(-(1 << 31), 1 << 31) b = random.randrange(-(1 << 31), 1 << 31) op = random.choice(self.ops) item = AluInputItem(op, a, b) await self.start_item(item) await self.finish_item(item) # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 50) # Sequencers self.alu_seqr = uvm_sequencer("alu_seqr", self) # Driver self.alu_drv = AluDriver("alu_drv", self, dut=cocotb.top) # Monitors self.inp_mon = AluInputMonitor("inp_mon", self, dut=cocotb.top) self.out_mon = AluOutputMonitor("out_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = AluScoreboard("scoreboard", self) def connect_phase(self): self.alu_drv.seq_item_port.connect(self.alu_seqr.seq_item_export) self.inp_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.out_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Syncrhonize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): # zero input signals cocotb.top.scan_mode.value = 0 cocotb.top.flush_upper_x.value = 0 cocotb.top.flush_lower_r.value = 0 cocotb.top.enable.value = 0 cocotb.top.valid_in.value = 0 cocotb.top.ap_clz.value = 0 cocotb.top.ap_ctz.value = 0 cocotb.top.ap_cpop.value = 0 cocotb.top.ap_sext_b.value = 0 cocotb.top.ap_sext_h.value = 0 cocotb.top.ap_min.value = 0 cocotb.top.ap_max.value = 0 cocotb.top.ap_pack.value = 0 cocotb.top.ap_packu.value = 0 cocotb.top.ap_packh.value = 0 cocotb.top.ap_rol.value = 0 cocotb.top.ap_ror.value = 0 cocotb.top.ap_grev.value = 0 cocotb.top.ap_gorc.value = 0 cocotb.top.ap_zbb.value = 0 cocotb.top.ap_bset.value = 0 cocotb.top.ap_bclr.value = 0 cocotb.top.ap_binv.value = 0 cocotb.top.ap_bext.value = 0 cocotb.top.ap_sh1add.value = 0 cocotb.top.ap_sh2add.value = 0 cocotb.top.ap_sh3add.value = 0 cocotb.top.ap_zba.value = 0 cocotb.top.ap_land.value = 0 cocotb.top.ap_lor.value = 0 cocotb.top.ap_lxor.value = 0 cocotb.top.ap_sll.value = 0 cocotb.top.ap_srl.value = 0 cocotb.top.ap_sra.value = 0 cocotb.top.ap_beq.value = 0 cocotb.top.ap_bne.value = 0 cocotb.top.ap_blt.value = 0 cocotb.top.ap_bge.value = 0 cocotb.top.ap_add.value = 0 cocotb.top.ap_sub.value = 0 cocotb.top.ap_slt.value = 0 cocotb.top.ap_unsignl.value = 0 cocotb.top.ap_jall.value = 0 cocotb.top.ap_predict_tl.value = 0 cocotb.top.ap_predict_nt.value = 0 cocotb.top.ap_csr_write.value = 0 cocotb.top.ap_csr_imm.value = 0 cocotb.top.csr_ren_in.value = 0 cocotb.top.csr_rddata_in.value = 0 cocotb.top.a_in.value = 0 cocotb.top.b_in.value = 0 cocotb.top.pc_in.value = 0 cocotb.top.brimm_in.value = 0 # perform reset cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() # Set common signals cocotb.top.enable.value = 1 # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/exu_div/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_exu_div_ctl_wrapper VERILOG_SOURCES = \ $(TEST_DIR)/el2_exu_div_ctl_wrapper.sv \ $(SRCDIR)/exu/el2_exu_div_ctl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/exu_div/config.vlt ================================================ `verilator_config lint_off -rule WIDTHTRUNC -file "*/el2_exu_div_ctl_wrapper.sv" lint_off -rule UNUSEDPARAM -file "*/el2_exu_div_ctl_wrapper.sv" ================================================ FILE: verification/block/exu_div/el2_exu_div_ctl_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_exu_div_ctl_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic scan_mode, // el2_div_pkt_t input logic dp_valid, input logic dp_unsign, input logic dp_rem, input logic [31:0] dividend, input logic [31:0] divisor, input logic cancel, output logic finish_dly, output logic [31:0] out ); // Pack el2_div_pkt_t el2_div_pkt_t dp; assign dp.valid = dp_valid; assign dp.unsign = dp_unsign; assign dp.rem = dp_rem; // The divider el2_exu_div_ctl div (.*); endmodule ================================================ FILE: verification/block/exu_div/test_div.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseSequence, BaseTest # ============================================================================= @pyuvm.test() class TestDiv(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["div"]) async def run(self): await self.seq.start(self.env.div_seqr) @pyuvm.test() class TestRem(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["rem"]) async def run(self): await self.seq.start(self.env.div_seqr) @pyuvm.test() class TestAll(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["div", "rem"]) async def run(self): await self.seq.start(self.env.div_seqr) ================================================ FILE: verification/block/exu_div/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import math import os import random import struct import pyuvm from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from pyuvm import * # ============================================================================== class DivInputItem(uvm_sequence_item): """ Divider input data """ def __init__(self, op, num, den, unsign=1): super().__init__("DivInputItem") self.op = op self.num = num self.den = den self.unsign = unsign class DivOutputItem(uvm_sequence_item): """ Divider output data """ def __init__(self, out): super().__init__("DivOutputItem") self.out = out # ============================================================================== class DivDriver(uvm_driver): """ Divider module driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, DivInputItem): # Wait for rising edge await RisingEdge(self.dut.clk) self.dut.dp_valid.value = 1 self.dut.dp_unsign.value = it.unsign self.dut.dp_rem.value = it.op == "rem" self.dut.dividend.value = it.num self.dut.divisor.value = it.den # Deassert valid, wait for finish for i in range(100): await RisingEdge(self.dut.clk) self.dut.dp_valid.value = 0 if self.dut.finish_dly.value: break else: raise RuntimeError("Timeout") else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class DivInputMonitor(uvm_component): """ Monitor for divider inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Act on rising edges await RisingEdge(self.dut.clk) # We got a valid input if self.dut.dp_valid.value: # Sample control signals and operands num = int(self.dut.dividend.value) den = int(self.dut.divisor.value) unsign = int(self.dut.dp_unsign.value) # Decode operation op = "rem" if self.dut.dp_rem.value else "div" # Write item self.ap.write(DivInputItem(op=op, num=num, den=den, unsign=unsign)) class DivOutputMonitor(uvm_component): """ Monitor for divider outputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Act on rising edges await RisingEdge(self.dut.clk) # We got a valid output if self.dut.finish_dly.value: # Sample result & write the item result = int(self.dut.out.value) self.ap.write(DivOutputItem(out=result)) # ============================================================================== class DivScoreboard(uvm_component): """ Divider scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True # Predict the result div = item_inp.num // item_inp.den rem = item_inp.num - (div * item_inp.den) self.logger.debug( "{} {} {} == {}".format( item_inp.num, item_inp.op, item_inp.den, item_out.out, ) ) # Check if (item_inp.op == "div" and item_out.out != div) or ( item_inp.op == "rem" and item_out.out != rem ): result = div if item_inp.op == "div" else rem self.logger.error( "{} {} {} != {} ({})".format( item_inp.num, item_inp.op, item_inp.den, result, item_out.out ) ) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseSequence(uvm_sequence): """ Base sequence of randomized 32-bit A and B operands along with operators picked randomly from the allowed set """ def __init__(self, name, ops=None): super().__init__(name) if ops is None: self.ops = ["div", "rem"] else: self.ops = ops async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") for i in range(count): num = random.randrange(1, 1 << 32) den = random.randrange(1, 1 << 16) # Make dividends from smaller range op = random.choice(self.ops) item = DivInputItem(op, num, den) await self.start_item(item) await self.finish_item(item) # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 50) # Sequencers self.div_seqr = uvm_sequencer("div_seqr", self) # Driver self.div_drv = DivDriver("div_drv", self, dut=cocotb.top) # Monitors self.inp_mon = DivInputMonitor("inp_mon", self, dut=cocotb.top) self.out_mon = DivOutputMonitor("out_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = DivScoreboard("scoreboard", self) def connect_phase(self): self.div_drv.seq_item_port.connect(self.div_seqr.seq_item_export) self.inp_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.out_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Syncrhonize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.scan_mode.value = 0 cocotb.top.dp_valid.value = 0 cocotb.top.dp_unsign.value = 0 cocotb.top.dp_rem.value = 0 cocotb.top.dividend.value = 0 cocotb.top.divisor.value = 0 cocotb.top.cancel.value = 0 cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/exu_mul/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_exu_mul_ctl_wrapper CM_FILE = cm.cfg VERILOG_SOURCES = \ $(TEST_DIR)/el2_exu_mul_ctl_wrapper.sv \ $(SRCDIR)/exu/el2_exu_mul_ctl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/exu_mul/cm.cfg ================================================ +tree el2_exu_mul_ctl_wrapper.mul -node el2_exu_mul_ctl_wrapper.mul.crc32_poly_rev // Tied to 32'hEDB88320 -node el2_exu_mul_ctl_wrapper.mul.crc32c_poly_rev // Tied to 32'h82F63B78 ================================================ FILE: verification/block/exu_mul/config.vlt ================================================ `verilator_config lint_off -rule WIDTHTRUNC -file "*/el2_exu_mul_ctl_wrapper.sv" lint_off -rule UNUSEDPARAM -file "*/el2_exu_mul_ctl_wrapper.sv" ================================================ FILE: verification/block/exu_mul/el2_exu_mul_ctl_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_exu_mul_ctl_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic rst_l, input logic scan_mode, // Unpacked mul_p input logic mul_p_valid, input logic mul_p_rs1_sign, input logic mul_p_rs2_sign, input logic mul_p_low, input logic mul_p_bcompress, input logic mul_p_bdecompress, input logic mul_p_clmul, input logic mul_p_clmulh, input logic mul_p_clmulr, input logic mul_p_grev, input logic mul_p_gorc, input logic mul_p_shfl, input logic mul_p_unshfl, input logic mul_p_crc32_b, input logic mul_p_crc32_h, input logic mul_p_crc32_w, input logic mul_p_crc32c_b, input logic mul_p_crc32c_h, input logic mul_p_crc32c_w, input logic mul_p_bfp, input logic mul_p_xperm_n, input logic mul_p_xperm_b, input logic mul_p_xperm_h, input logic [31:0] rs1_in, input logic [31:0] rs2_in, output logic [31:0] result_x ); // Pack mul_p el2_mul_pkt_t mul_p; assign mul_p.valid = mul_p_valid; assign mul_p.rs1_sign = mul_p_rs1_sign; assign mul_p.rs2_sign = mul_p_rs2_sign; assign mul_p.low = mul_p_low; assign mul_p.bcompress = mul_p_bcompress; assign mul_p.bdecompress = mul_p_bdecompress; assign mul_p.clmul = mul_p_clmul; assign mul_p.clmulh = mul_p_clmulh; assign mul_p.clmulr = mul_p_clmulr; assign mul_p.grev = mul_p_grev; assign mul_p.gorc = mul_p_gorc; assign mul_p.shfl = mul_p_shfl; assign mul_p.unshfl = mul_p_unshfl; assign mul_p.crc32_b = mul_p_crc32_b; assign mul_p.crc32_h = mul_p_crc32_h; assign mul_p.crc32_w = mul_p_crc32_w; assign mul_p.crc32c_b = mul_p_crc32c_b; assign mul_p.crc32c_h = mul_p_crc32c_h; assign mul_p.crc32c_w = mul_p_crc32c_w; assign mul_p.bfp = mul_p_bfp; assign mul_p.xperm_n = mul_p_xperm_n; assign mul_p.xperm_b = mul_p_xperm_b; assign mul_p.xperm_h = mul_p_xperm_h; // The multiplier el2_exu_mul_ctl mul (.*); endmodule ================================================ FILE: verification/block/exu_mul/test_mul.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseSequence, BaseTest # ============================================================================= @pyuvm.test() class TestMul(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BaseSequence("stimulus", ["mul"]) async def run(self): await self.seq.start(self.env.mul_seqr) ================================================ FILE: verification/block/exu_mul/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import math import os import random import struct import pyuvm from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from pyuvm import * # ============================================================================== class MulInputItem(uvm_sequence_item): """ Multipiler input data """ def __init__(self, op, a, b, low=0): super().__init__("MulInputItem") self.op = op self.a = a self.b = b self.low = low class MulOutputItem(uvm_sequence_item): """ Multiplier output data """ def __init__(self, out): super().__init__("MulOutputItem") self.out = out # ============================================================================== class MulDriver(uvm_driver): """ Multiplier input driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, MulInputItem): # Wait for rising edge await RisingEdge(self.dut.clk) self.dut.mul_p_valid.value = 1 # Operands self.dut.rs1_in.value = abs(it.a) self.dut.rs2_in.value = abs(it.b) self.dut.mul_p_rs1_sign.value = 0 # For now assume positive self.dut.mul_p_rs2_sign.value = 0 # Control self.dut.mul_p_low.value = it.low # Deassert valid after one cycle await RisingEdge(self.dut.clk) self.dut.mul_p_valid.value = 0 else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class MulInputMonitor(uvm_component): """ Monitor for Multiplier inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Act on rising edges await RisingEdge(self.dut.clk) # We got a valid input if self.dut.mul_p_valid.value: # Sample control signals and operands a = int(self.dut.rs1_in.value) b = int(self.dut.rs2_in.value) low = int(self.dut.mul_p_low.value) # Decode operation op = None # Write item self.ap.write( MulInputItem( op=op, a=a, b=b, low=low, ) ) class MulOutputMonitor(uvm_component): """ Monitor for multiplier outputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Act on rising edges await RisingEdge(self.dut.clk) # We got a valid input if self.dut.mul_p_valid.value: # Wait 1 cycle await RisingEdge(self.dut.clk) # Sample result & write the item result = int(self.dut.result_x.value) self.ap.write(MulOutputItem(out=result)) # ============================================================================== class MulScoreboard(uvm_component): """ Generic ALU scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True # Predict the result res = item_inp.a * item_inp.b if not item_inp.low: res >>= 32 res &= 0xFFFFFFFF self.logger.debug( "{} * {} ({}) == {}".format( item_inp.a, item_inp.b, "lo" if item_inp.low else "hi", item_out.out, ) ) if item_out.out != res: self.logger.error( "{} * {} ({}) != {} (should be {})".format( item_inp.a, item_inp.b, "lo" if item_inp.low else "hi", item_out.out, res ) ) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseSequence(uvm_sequence): """ Base sequence of randomized 32-bit A and B operands along with operators picked randomly from the allowed set """ def __init__(self, name, ops=None): super().__init__(name) if ops is None: self.ops = ["mul"] else: self.ops = ops async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") for i in range(count): a = random.randrange(1, 1 << 32) b = random.randrange(1, 1 << 32) op = random.choice(self.ops) if op == "mul": low = random.choice([0, 1]) item = MulInputItem(op, a, b, low=low) await self.start_item(item) await self.finish_item(item) # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 50) # Sequencers self.mul_seqr = uvm_sequencer("mul_seqr", self) # Driver self.mul_drv = MulDriver("mul_drv", self, dut=cocotb.top) # Monitors self.inp_mon = MulInputMonitor("inp_mon", self, dut=cocotb.top) self.out_mon = MulOutputMonitor("out_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = MulScoreboard("scoreboard", self) def connect_phase(self): self.mul_drv.seq_item_port.connect(self.mul_seqr.seq_item_export) self.inp_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.out_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Syncrhonize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): # zero input signals cocotb.top.scan_mode.value = 0 cocotb.top.mul_p_valid.value = 0 cocotb.top.mul_p_rs1_sign.value = 0 cocotb.top.mul_p_rs2_sign.value = 0 cocotb.top.mul_p_low.value = 0 cocotb.top.mul_p_bcompress.value = 0 cocotb.top.mul_p_bdecompress.value = 0 cocotb.top.mul_p_clmul.value = 0 cocotb.top.mul_p_clmulh.value = 0 cocotb.top.mul_p_clmulr.value = 0 cocotb.top.mul_p_grev.value = 0 cocotb.top.mul_p_gorc.value = 0 cocotb.top.mul_p_shfl.value = 0 cocotb.top.mul_p_unshfl.value = 0 cocotb.top.mul_p_crc32_b.value = 0 cocotb.top.mul_p_crc32_h.value = 0 cocotb.top.mul_p_crc32_w.value = 0 cocotb.top.mul_p_crc32c_b.value = 0 cocotb.top.mul_p_crc32c_h.value = 0 cocotb.top.mul_p_crc32c_w.value = 0 cocotb.top.mul_p_bfp.value = 0 cocotb.top.mul_p_xperm_n.value = 0 cocotb.top.mul_p_xperm_b.value = 0 cocotb.top.mul_p_xperm_h.value = 0 cocotb.top.rs1_in.value = 0 cocotb.top.rs2_in.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/iccm/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_ifu_iccm_mem_wrapper VERILOG_SOURCES = \ $(SRCDIR)/lib/el2_mem_if.sv \ $(TEST_DIR)/el2_ifu_iccm_mem_wrapper.sv \ $(SRCDIR)/ifu/el2_ifu_iccm_mem.sv \ $(SRCDIR)/lib/mem_lib.sv # Undefine the VERILATOR macro to make the code use actual RAM cells instead # of simulation models EXTRA_ARGS += -UVERILATOR include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/iccm/config.vlt ================================================ `verilator_config lint_off -rule PINCONNECTEMPTY -file "*/el2_ifu_iccm_mem_wrapper.sv" lint_off -rule WIDTHTRUNC -file "*/el2_ifu_iccm_mem_wrapper.sv" lint_off -rule IMPORTSTAR -file "*/el2_mem_if.sv" ================================================ FILE: verification/block/iccm/el2_ifu_iccm_mem_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_ifu_iccm_mem_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic active_clk, input logic rst_l, input logic clk_override, input logic iccm_wren, input logic iccm_rden, input logic [pt.ICCM_BITS-1:1] iccm_rw_addr, input logic iccm_buf_correct_ecc, input logic iccm_correction_state, input logic [2:0] iccm_wr_size, input logic [77:0] iccm_wr_data, // Unwrapped iccm_ext_in_pkt input logic iccm_ext_in_pkt_TEST1, input logic iccm_ext_in_pkt_RME, input logic [3:0] iccm_ext_in_pkt_RM, input logic iccm_ext_in_pkt_LS, input logic iccm_ext_in_pkt_DS, input logic iccm_ext_in_pkt_SD, input logic iccm_ext_in_pkt_TEST_RNM, input logic iccm_ext_in_pkt_BC1, input logic iccm_ext_in_pkt_BC2, output logic [63:0] iccm_rd_data, output logic [77:0] iccm_rd_data_ecc, input logic scan_mode ); logic [pt.ICCM_NUM_BANKS-1:0] iccm_clken; logic [pt.ICCM_NUM_BANKS-1:0] iccm_wren_bank; logic [pt.ICCM_NUM_BANKS-1:0][pt.ICCM_BITS-1:pt.ICCM_BANK_INDEX_LO] iccm_addr_bank; logic [pt.ICCM_NUM_BANKS-1:0][ 31:0] iccm_bank_wr_data; logic [pt.ICCM_NUM_BANKS-1:0][ pt.ICCM_ECC_WIDTH-1:0] iccm_bank_wr_ecc; logic [pt.ICCM_NUM_BANKS-1:0][ 31:0] iccm_bank_dout; logic [pt.ICCM_NUM_BANKS-1:0][ pt.ICCM_ECC_WIDTH-1:0] iccm_bank_ecc; logic [pt.ICCM_NUM_BANKS-1:0][ 38:0] iccm_bank_wr_fdata; logic [pt.ICCM_NUM_BANKS-1:0][ 38:0] iccm_bank_fdout; el2_mem_if mem_export (); assign iccm_clken = mem_export.iccm_clken; assign iccm_wren_bank = mem_export.iccm_wren_bank; assign iccm_addr_bank = mem_export.iccm_addr_bank; assign iccm_bank_wr_data = mem_export.iccm_bank_wr_data; assign iccm_bank_wr_ecc = mem_export.iccm_bank_wr_ecc; // Pack el2_ccm_ext_in_pkt_t el2_ccm_ext_in_pkt_t [pt.ICCM_NUM_BANKS-1:0] iccm_ext_in_pkt; for (genvar i = 0; i < pt.ICCM_NUM_BANKS; i++) begin : gen_iccm_ext_pkt assign iccm_ext_in_pkt[i].TEST1 = iccm_ext_in_pkt_TEST1; assign iccm_ext_in_pkt[i].RME = iccm_ext_in_pkt_RME; assign iccm_ext_in_pkt[i].RM = iccm_ext_in_pkt_RM; assign iccm_ext_in_pkt[i].LS = iccm_ext_in_pkt_LS; assign iccm_ext_in_pkt[i].DS = iccm_ext_in_pkt_DS; assign iccm_ext_in_pkt[i].SD = iccm_ext_in_pkt_SD; assign iccm_ext_in_pkt[i].TEST_RNM = iccm_ext_in_pkt_TEST_RNM; assign iccm_ext_in_pkt[i].BC1 = iccm_ext_in_pkt_BC1; assign iccm_ext_in_pkt[i].BC2 = iccm_ext_in_pkt_BC2; end : gen_iccm_ext_pkt // The ICCM module for (genvar i = 0; i < pt.ICCM_NUM_BANKS; i++) begin : gen_iccm_mem assign iccm_bank_wr_fdata[i] = { mem_export.iccm_bank_wr_ecc[i], mem_export.iccm_bank_wr_data[i] }; assign mem_export.iccm_bank_dout[i] = iccm_bank_fdout[i][31:0]; assign mem_export.iccm_bank_ecc[i] = iccm_bank_fdout[i][32+pt.ICCM_ECC_WIDTH-1:32]; el2_ram #( .depth(1 << pt.ICCM_INDEX_BITS), .width(39) ) iccm_bank ( // Primary ports .ME(iccm_clken[i]), .CLK(clk), .WE(iccm_wren_bank[i]), .ADR(iccm_addr_bank[i]), .D(iccm_bank_wr_fdata[i][38:0]), .Q(iccm_bank_fdout[i][38:0]), .ROP(), // These are used by SoC .TEST1(iccm_ext_in_pkt[i].TEST1), .RME(iccm_ext_in_pkt[i].RME), .RM(iccm_ext_in_pkt[i].RM), .LS(iccm_ext_in_pkt[i].LS), .DS(iccm_ext_in_pkt[i].DS), .SD(iccm_ext_in_pkt[i].SD), .TEST_RNM(iccm_ext_in_pkt[i].TEST_RNM), .BC1(iccm_ext_in_pkt[i].BC1), .BC2(iccm_ext_in_pkt[i].BC2) ); end : gen_iccm_mem el2_ifu_iccm_mem mem ( .iccm_mem_export(mem_export.veer_iccm), .* ); endmodule ================================================ FILE: verification/block/iccm/test_readwrite.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from pyuvm import * from testbench import BaseTest, MemReadItem, MemWriteItem # ============================================================================= class ReadWriteSequence(uvm_sequence): """ A sequencer that issues a random sequence of writes followed by a randomized sequence of reads containing the same addresses previously written to. """ def __init__(self, name): super().__init__(name) async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") burst = ConfigDB().get(None, "", "TEST_BURST_LEN") awidth = ( ConfigDB().get(None, "", "ICCM_BITS") - 1 ) # Address input declared as [pt.ICCM_BITS-1:1] dwidth = 64 # Fixed for i in range(count): # Randomize unique addresses (aligned to 8) addrs = set([random.randrange(0, 1 << awidth) & ~7 for i in range(burst)]) # Issue writes, randomize data for addr in addrs: data = random.randrange(0, 1 << dwidth) item = MemWriteItem(addr, data) await self.start_item(item) await self.finish_item(item) # Issue random reads for written addresses addrs = list(set(addrs)) random.shuffle(addrs) for addr in addrs: item = MemReadItem(addr, data) await self.start_item(item) await self.finish_item(item) @pyuvm.test() class TestReadWrite(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = ReadWriteSequence("stimulus") async def run(self): await self.seq.start(self.env.mem_seqr) ================================================ FILE: verification/block/iccm/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import os from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge from pyuvm import * # ============================================================================== class MemWriteItem(uvm_sequence_item): """ Memory write item """ def __init__(self, addr, data): super().__init__("MemWriteItem") self.addr = addr self.data = data class MemReadItem(uvm_sequence_item): """ Memory read item """ def __init__(self, addr, data=None): super().__init__("MemReadItem") self.addr = addr self.data = data # ============================================================================== class MemDriver(uvm_driver): """ Memory interface driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() # Write if isinstance(it, MemWriteItem): # Wait for rising edge, do the write await RisingEdge(self.dut.clk) self.dut.iccm_wren.value = 1 self.dut.iccm_rw_addr.value = it.addr self.dut.iccm_wr_data.value = it.data self.dut.iccm_wr_size.value = 7 # FIXME: Fixed 64-bit writes for now # Wait for rising edge, deassert write await RisingEdge(self.dut.clk) self.dut.iccm_wren.value = 0 # Read elif isinstance(it, MemReadItem): # Wait for rising edge, do the read await RisingEdge(self.dut.clk) self.dut.iccm_rden.value = 1 self.dut.iccm_rw_addr.value = it.addr # Wait for rising edge, deassert read await RisingEdge(self.dut.clk) self.dut.iccm_rden.value = 0 else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class MemMonitor(uvm_component): """ Memory interface monitor """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Act on rising edges await RisingEdge(self.dut.clk) # Since the driver drives both lo and hi with the same values # here we sample only lo # Write if self.dut.iccm_wren.value: addr = int(self.dut.iccm_rw_addr) data = int(self.dut.iccm_wr_data) self.ap.write(MemWriteItem(addr, data)) # Read if self.dut.iccm_rden.value: addr = int(self.dut.iccm_rw_addr) # Wait additional clock cycle await RisingEdge(self.dut.clk) # FIXME: For now read just raw data, not the ECC-corrected part data = int(self.dut.iccm_rd_data_ecc) self.ap.write(MemReadItem(addr, data)) # ============================================================================== class Scoreboard(uvm_component): """ A scoreboard that tracks memory writes and compares them agains data read from the memory. It also checks if both reads and writes took place """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): did_write = False did_read = False mem_content = dict() # Process items while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Initially pass if self.passed is None: self.passed = True # Memory write if isinstance(item, MemWriteItem): mem_content[item.addr] = item.data did_write = True self.logger.debug("[0x{:08X}] <= 0x{:08X}".format(item.addr, item.data)) # Memory read elif isinstance(item, MemReadItem): data = mem_content.get(item.addr, None) did_read = True self.logger.debug( "[0x{:08X}] == 0x{:08X} vs. 0x{:08X} {}".format( item.addr, item.data, data, item.data == data ) ) if data != item.data: self.logger.error( "Data mismatch, mem[0x{:08X}] is 0x{:08X}, should be 0x{:08X}".format( item.addr, item.data, data ) ) self.passed = False # There were no writes if not did_write: self.logger.error("There were no writes") self.passed = False # There were no reads if not did_read: self.logger.error("There were no reads") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 50) ConfigDB().set(None, "*", "TEST_BURST_LEN", 10) ConfigDB().set(None, "*", "ICCM_BITS", 0x10) # Sequencers self.mem_seqr = uvm_sequencer("mem_seqr", self) # Driver self.mem_drv = MemDriver("mem_drv", self, dut=cocotb.top) # Monitor self.mem_mon = MemMonitor("mem_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): self.mem_drv.seq_item_port.connect(self.mem_seqr.seq_item_export) self.mem_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.active_clk.value = 0 cocotb.top.clk_override.value = 0 cocotb.top.iccm_wren.value = 0 cocotb.top.iccm_rden.value = 0 cocotb.top.iccm_rw_addr.value = 0 cocotb.top.iccm_buf_correct_ecc.value = 0 cocotb.top.iccm_correction_state.value = 0 cocotb.top.iccm_wr_size.value = 0 cocotb.top.iccm_wr_data.value = 0 cocotb.top.iccm_ext_in_pkt_TEST1.value = 0 cocotb.top.iccm_ext_in_pkt_RME.value = 0 cocotb.top.iccm_ext_in_pkt_RM.value = 0 cocotb.top.iccm_ext_in_pkt_LS.value = 0 cocotb.top.iccm_ext_in_pkt_DS.value = 0 cocotb.top.iccm_ext_in_pkt_SD.value = 0 cocotb.top.iccm_ext_in_pkt_TEST_RNM.value = 0 cocotb.top.iccm_ext_in_pkt_BC1.value = 0 cocotb.top.iccm_ext_in_pkt_BC2.value = 0 cocotb.top.scan_mode.value = 0 cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") self.start_clock("active_clk") # Issue reset await self.do_reset() # Set constant value signals cocotb.top.iccm_buf_correct_ecc.value = 0 cocotb.top.iccm_correction_state.value = 0 # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/ifu_compress/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_ifu_compress_ctl CM_FILE = cm.cfg VERILOG_SOURCES = \ $(SRCDIR)/ifu/el2_ifu_compress_ctl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/ifu_compress/cm.cfg ================================================ +tree * // Tied to '0 -node el2_ifu_compress_ctl.o[31] -node el2_ifu_compress_ctl.o[29:21] -node el2_ifu_compress_ctl.o[19:15] -node el2_ifu_compress_ctl.o[11:7] -node el2_ifu_compress_ctl.o[1:0] // Tied to 2'b11 -node el2_ifu_compress_ctl.l1[1:0] // Tied to o[1:0] (2'b11) -node el2_ifu_compress_ctl.l2[1:0] // Tied to l1[1:0] (2'b11) -node el2_ifu_compress_ctl.l3[1:0] // Tied to l2[1:0] (2'b11) -node el2_ifu_compress_ctl.l1[31] // Tied to o[31] ('0) -node el2_ifu_compress_ctl.l1[29:25] // Tied to o[29:25] ('0) -node el2_ifu_compress_ctl.rdpd[4:3] // Tied to 2'01 -node el2_ifu_compress_ctl.rs2pd[4:3] // Tied to 2'01 ================================================ FILE: verification/block/ifu_compress/test_compress.py ================================================ import pyuvm from pyuvm import * from testbench import BaseEnv, BaseTest, CompressedSequence @pyuvm.test() class TestDecompressor(BaseTest): """ Decompression test """ def __init__(self, name, parent): super().__init__(name, parent, BaseEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = CompressedSequence.create("stimulus") async def run(self): await self.seq.start(self.env.dcm_seqr) ================================================ FILE: verification/block/ifu_compress/testbench.py ================================================ import os import random import subprocess import textwrap from queue import Queue import pyuvm from cocotb.binary import BinaryValue from cocotb.triggers import Timer from pyuvm import * def collect_signals(signals, uut, obj, uut_prefix="", obj_prefix=""): """ Collects signal objects from UUT and attaches them to the given object. Optionally UUT signals can be prefixed with the uut_prefix and object signals with the obj_prefix """ for sig in signals: uut_sig = uut_prefix + sig obj_sig = obj_prefix + sig if hasattr(uut, uut_sig): s = getattr(uut, uut_sig) else: s = None logging.error("Module {} does not have a signal '{}'".format(str(uut), sig)) setattr(obj, obj_sig, s) def get_opcode(asm_line, ext="rv32i", size=32): """ Generates binary opcode string based on a line of assembly """ cmd = f"echo '{asm_line}' | riscv64-unknown-elf-as -march={ext} -o /dev/null -al | tail -n 1" # Take instruction hex (3rd column) and change its endianess out = subprocess.check_output([cmd], shell=True).decode().split()[2] out = "".join(textwrap.wrap(out, 2)[::-1]) assert len(out) == size // 4, f"instruction '{asm_line}' assembled to unexpected width" # Convert hex to bin opcode = f"{int(out, 16):0{size}b}" return opcode def generate_assembly_pair(): """ Generates random assembly instruction that can be compressed """ # For most compressed instructions only x8--x15 are allowed dreg = random.randrange(8, 16) sreg = random.randrange(8, 16) imm = random.randrange(2**11) sgn = random.choice(["-", ""]) # In f-strings below: # {imm%width} -- when the immediate's magnitude has a limited width # {imm or 1} -- when the immediate cannot be 0 # {sgn}{imm} -- when the immediate is signed return random.choice( [ (f"c.add x{dreg}, x{sreg}", f"add x{dreg}, x{dreg}, x{sreg}"), (f"c.or x{dreg}, x{sreg}", f"or x{dreg}, x{dreg}, x{sreg}"), (f"c.xor x{dreg}, x{sreg}", f"xor x{dreg}, x{dreg}, x{sreg}"), (f"c.sub x{dreg}, x{sreg}", f"sub x{dreg}, x{dreg}, x{sreg}"), (f"c.mv x{dreg}, x{sreg}", f"add x{dreg}, x0, x{sreg}"), (f"c.andi x{dreg}, {sgn}{imm % 5}", f"andi x{dreg}, x{dreg}, {sgn}{imm % 5}"), (f"c.addi x{dreg}, {sgn}{imm % 5}", f"addi x{dreg}, x{dreg}, {sgn}{imm % 5}"), (f"c.srli x{dreg}, {imm % 5 or 1}", f"srli x{dreg}, x{dreg}, {imm % 5 or 1}"), (f"c.srai x{dreg}, {imm % 5 or 1}", f"srai x{dreg}, x{dreg}, {imm % 5 or 1}"), (f"c.slli x{dreg}, {imm % 5 or 1}", f"slli x{dreg}, x{dreg}, {imm % 5 or 1}"), ("c.ebreak", "ebreak"), ] ) class CompressedGenerator: """ Generates compressed instructions and caches their expected decompressed counterpart to allow fast checks """ lookup = {} @classmethod def get(self): """ Generates compressed/decompressed instruction pair """ asm_com, asm_dec = generate_assembly_pair() com = get_opcode(asm_com, ext="rv32ic", size=16) dec = get_opcode(asm_dec, ext="rv32i", size=32) self.lookup[com] = dec return com @classmethod def check(self, com, dec): """ Checks if a previously generated instruction corresponds to the decompressed one given """ assert com in self.lookup, f"instruction 0b{com} not generated before" return self.lookup[com] == dec class InstructionPairItem(uvm_sequence_item): """ A generic instruction-input stimulus """ def __init__(self, din, dout): super().__init__("InstructionItem") """ Records a state of decompressor's pins """ self.din = din self.dout = dout class CompressedInstructionItem(uvm_sequence_item): """ A generic compressed instruction-input stimulus """ def __init__(self): super().__init__("CompressedInstructionItem") """ Creates a 16-bit instruction """ instr = CompressedGenerator.get() self.instr = BinaryValue(value=instr, bigEndian=False) class CompressedSequence(uvm_sequence): """ A sequencer that generates random RISC-V compressed instructions """ def __init__(self, name): super().__init__(name) async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") for j in range(count): # Create a compressed instruction item = CompressedInstructionItem() await self.start_item(item) await self.finish_item(item) class DecompressorDriver(uvm_driver): """ A driver for the IFU instruction decompressor """ SIGNALS = ["din", "dout"] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) # Collect signals collect_signals(self.SIGNALS, uut, self) async def write(self, instr): """ Pushes instruction to the decompressor """ self.din.value = instr await Timer(10, "us") async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, CompressedInstructionItem): await self.write(it.instr) else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class DecompressorMonitor(uvm_component): """ A monitor for the IFU instruction decompressor """ SIGNALS = ["din", "dout"] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: await Timer(10, "us") it = InstructionPairItem(self.din, self.dout) self.ap.write(it) class Scoreboard(uvm_component): """ Checks if all decompressed instructions have the expected value """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): # Process items while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Initially pass if self.passed is None: self.passed = True # Got a decompressed instruction which is incorrect if isinstance(item, InstructionPairItem): if not CompressedGenerator.check(str(item.din.value), str(item.dout.value)): self.logger.debug( "Instruction decompressed incorrectly: 0b{} -> 0b{}".format( item.din, item.dout ) ) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_ITERATIONS", 500) # Sequencers self.dcm_seqr = uvm_sequencer("dcm_seqr", self) # Driver self.dcm_drv = DecompressorDriver("dcm_drv", self, uut=cocotb.top) # Monitor self.dcm_mon = DecompressorMonitor("dcm_mon", self, uut=cocotb.top) # Scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): self.dcm_drv.seq_item_port.connect(self.dcm_seqr.seq_item_export) self.dcm_mon.ap.connect(self.scoreboard.fifo.analysis_export) class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) async def run_phase(self): self.raise_objection() await self.run() self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/ifu_mem_ctl/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_ifu_mem_ctl_wrapper CM_FILE = cm.cfg VERILOG_SOURCES = \ $(SRCDIR)/ifu/el2_ifu_mem_ctl.sv \ $(TEST_DIR)/el2_ifu_mem_ctl_wrapper.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/ifu_mem_ctl/cm.cfg ================================================ +tree el2_ifu_mem_ctl_wrapper.ifu_mem_ctl // Tied to '0 -node el2_ifu_mem_ctl_wrapper.ifu_mem_ctl.ifu_axi_araddr[2:0] ================================================ FILE: verification/block/ifu_mem_ctl/common.py ================================================ import random import cocotb from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge ICCM_BASE = 0xEE000000 ICCM_SIZE = 0x10000 class Axi4LiteBFM: def __init__(self, dut): self.dut = dut async def _wait(self, signal, max_cycles=200): """ Waits for a signal to be asserted in at most max_cycles. Raises an exception if it does not """ for _ in range(max_cycles): await RisingEdge(self.dut.clk) if signal.value != 0: break else: raise RuntimeError("{} timeout".format(signal._name)) async def read_handler(self): while True: if not self.dut.rst_l.value: await RisingEdge(self.dut.rst_l) self.dut.ifu_axi_arready.value = 1 await self._wait(self.dut.ifu_axi_arvalid) self.dut.ifu_axi_arready.value = 0 self.dut.ifu_axi_rvalid.value = 1 self.dut.ifu_axi_rdata.value = rand_iccm_data() self.dut.ifu_axi_rresp.value = 0 await RisingEdge(self.dut.clk) self.dut.ifu_axi_rvalid.value = 0 self.dut.ifu_axi_rdata.value = 0 self.dut.ifu_axi_rresp.value = 0 async def reset(dut): # Apply reset (active-low) dut.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) dut.rst_l.value = 1 await ClockCycles(cocotb.top.clk, 2) cocotb.top.ifu_bus_clk_en.value = 1 async def initialize(dut): dut.active_clk.value = 0 dut.free_l2clk.value = 0 dut.exu_flush_final.value = 0 dut.dec_tlu_flush_lower_wb.value = 0 dut.dec_tlu_flush_err_wb.value = 0 dut.dec_tlu_i0_commit_cmt.value = 0 dut.dec_tlu_force_halt.value = 0 dut.ifc_fetch_addr_bf.value = 0 dut.ifc_fetch_uncacheable_bf.value = 0 dut.ifc_fetch_req_bf.value = 0 dut.ifc_fetch_req_bf_raw.value = 0 dut.ifc_iccm_access_bf.value = 0 dut.ifc_region_acc_fault_bf.value = 0 dut.ifc_dma_access_ok.value = 0 dut.dec_tlu_fence_i_wb.value = 0 dut.ifu_bp_hit_taken_f.value = 0 dut.ifu_bp_inst_mask_f.value = 0 dut.ifu_axi_arready.value = 0 dut.ifu_axi_rvalid.value = 0 dut.ifu_axi_rid.value = 0 dut.ifu_axi_rdata.value = 0 dut.ifu_axi_rresp.value = 0 dut.ifu_bus_clk_en.value = 0 dut.dma_iccm_req.value = 0 dut.dma_mem_addr.value = 0 dut.dma_mem_sz.value = 0 dut.dma_mem_write.value = 0 dut.dma_mem_wdata.value = 0 dut.dma_mem_tag.value = 0 dut.ic_rd_data.value = 0 dut.ic_debug_rd_data.value = 0 dut.ictag_debug_rd_data.value = 0 dut.ic_eccerr.value = 0 dut.ic_parerr.value = 0 dut.ic_rd_hit.value = 0 dut.ic_tag_perr.value = 0 dut.iccm_rd_data.value = 0 dut.iccm_rd_data_ecc.value = 0 dut.ifu_fetch_val.value = 0 dut.icache_wrdata.value = 0 dut.icache_dicawics.value = 0 dut.icache_rd_valid.value = 0 dut.icache_wr_valid.value = 0 dut.dec_tlu_core_ecc_disable.value = 0 dut.ifu_pmp_error.value = 0 dut.scan_mode.value = 0 cocotb.start_soon(Clock(dut.clk, 1, units="ns").start()) cocotb.start_soon(Clock(dut.active_clk, 1, units="ns").start()) cocotb.start_soon(Clock(dut.free_l2clk, 1, units="ns").start()) axi_bfm = Axi4LiteBFM(dut) cocotb.start_soon(axi_bfm.read_handler()) await reset(dut) async def write(dut, addr, wdata): await RisingEdge(dut.clk) dut.dma_iccm_req.value = 1 dut.dma_mem_addr.value = addr dut.dma_mem_write.value = 1 dut.dma_mem_wdata.value = wdata await RisingEdge(dut.clk) dut.dma_iccm_req.value = 0 dut.dma_mem_addr.value = 0 dut.dma_mem_write.value = 0 dut.dma_mem_wdata.value = 0 async def read(dut, addr): await RisingEdge(dut.clk) dut.dma_iccm_req.value = 1 dut.dma_mem_write.value = 0 dut.dma_mem_addr.value = addr def rand_iccm_addr(): return random.randint(ICCM_BASE, ICCM_BASE + ICCM_SIZE) def rand_iccm_data(): return random.randint(0, (2**64) - 1) def rand_ifu_addr(): return random.randint(0, (2**31) - 1) def get_bitflip_mask(do_double_bit): return 2 << (random.randint(0, 2**32 - 1) % (37)) | ((2**40) & ((2**40) - do_double_bit)) ================================================ FILE: verification/block/ifu_mem_ctl/el2_ifu_mem_ctl_wrapper.sv ================================================ module el2_ifu_mem_ctl_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic free_l2clk, // Clock always. Through one clock header. For flops with second header built in. input logic rst_l, // reset, active low input logic exu_flush_final, // Flush from the pipeline., includes flush lower input logic dec_tlu_flush_lower_wb, // Flush lower from the pipeline. input logic dec_tlu_flush_err_wb, // Flush from the pipeline due to perr. input logic dec_tlu_i0_commit_cmt, // committed i0 instruction input logic dec_tlu_force_halt, // force halt. input logic [31:1] ifc_fetch_addr_bf, // Fetch Address byte aligned always. F1 stage. input logic ifc_fetch_uncacheable_bf, // The fetch request is uncacheable space. F1 stage input logic ifc_fetch_req_bf, // Fetch request. Comes with the address. F1 stage input logic ifc_fetch_req_bf_raw, // Fetch request without some qualifications. Used for clock-gating. F1 stage input logic ifc_iccm_access_bf, // This request is to the ICCM. Do not generate misses to the bus. input logic ifc_region_acc_fault_bf, // Access fault. in ICCM region but offset is outside defined ICCM. input logic ifc_dma_access_ok, // It is OK to give dma access to the ICCM. (ICCM is not busy this cycle). input logic dec_tlu_fence_i_wb, // Fence.i instruction is committing. Clear all Icache valids. input logic ifu_bp_hit_taken_f, // Branch is predicted taken. Kill the fetch next cycle. input logic ifu_bp_inst_mask_f, // tell ic which valids to kill because of a taken branch, right justified output logic ifu_miss_state_idle, // No icache misses are outstanding. output logic ifu_ic_mb_empty, // Continue with normal fetching. This does not mean that miss is finished. output logic ic_dma_active , // In the middle of servicing dma request to ICCM. Do not make any new requests. output logic ic_write_stall, // Stall fetch the cycle we are writing the cache. /// PMU signals output logic ifu_pmu_ic_miss, // IC miss event output logic ifu_pmu_ic_hit, // IC hit event output logic ifu_pmu_bus_error, // Bus error event output logic ifu_pmu_bus_busy, // Bus busy event output logic ifu_pmu_bus_trxn, // Bus transaction //-------------------------- IFU AXI signals-------------------------- // AXI Write Channels /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic ifu_axi_awvalid, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_awid, output logic [ 31:0] ifu_axi_awaddr, output logic [ 3:0] ifu_axi_awregion, output logic [ 7:0] ifu_axi_awlen, output logic [ 2:0] ifu_axi_awsize, output logic [ 1:0] ifu_axi_awburst, output logic ifu_axi_awlock, output logic [ 3:0] ifu_axi_awcache, output logic [ 2:0] ifu_axi_awprot, output logic [ 3:0] ifu_axi_awqos, output logic ifu_axi_wvalid, output logic [63:0] ifu_axi_wdata, output logic [ 7:0] ifu_axi_wstrb, output logic ifu_axi_wlast, output logic ifu_axi_bready, /*pragma coverage on*/ // AXI Read Channels output logic ifu_axi_arvalid, input logic ifu_axi_arready, output logic [pt.IFU_BUS_TAG-1:0] ifu_axi_arid, output logic [ 31:0] ifu_axi_araddr, output logic [ 3:0] ifu_axi_arregion, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic [ 7:0] ifu_axi_arlen, output logic [ 2:0] ifu_axi_arsize, output logic [ 1:0] ifu_axi_arburst, output logic ifu_axi_arlock, output logic [ 3:0] ifu_axi_arcache, output logic [ 2:0] ifu_axi_arprot, output logic [ 3:0] ifu_axi_arqos, /*pragma coverage on*/ input logic ifu_axi_rvalid, /* exclude signals that are tied to constant value in this file */ /*pragma coverage off*/ output logic ifu_axi_rready, /*pragma coverage on*/ input logic [pt.IFU_BUS_TAG-1:0] ifu_axi_rid, input logic [ 63:0] ifu_axi_rdata, input logic [ 1:0] ifu_axi_rresp, input logic ifu_bus_clk_en, input logic dma_iccm_req, // dma iccm command (read or write) input logic [31:0] dma_mem_addr, // dma address input logic [ 2:0] dma_mem_sz, // size input logic dma_mem_write, // write input logic [63:0] dma_mem_wdata, // write data input logic [ 2:0] dma_mem_tag, // DMA Buffer entry number output logic iccm_dma_ecc_error, // Data read from iccm has an ecc error output logic iccm_dma_rvalid, // Data read from iccm is valid output logic [63:0] iccm_dma_rdata, // dma data read from iccm output logic [ 2:0] iccm_dma_rtag, // Tag of the DMA req output logic iccm_ready, // iccm ready to accept new command. // I$ & ITAG Ports output logic [31:1] ic_rw_addr, // Read/Write addresss to the Icache. output logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en, // Icache write enable, when filling the Icache. output logic ic_rd_en, // Icache read enable. output logic [pt.ICACHE_BANKS_WAY-1:0] [70:0] ic_wr_data, // Data to fill to the Icache. With ECC input logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [25:0] ictag_debug_rd_data, // Debug icache tag. output logic [70:0] ic_debug_wr_data, // Debug wr cache. output logic [70:0] ifu_ic_debug_rd_data, // debug data read input logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, // input logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, output logic [ pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. output logic ic_debug_rd_en, // Icache debug rd output logic ic_debug_wr_en, // Icache debug wr output logic ic_debug_tag_array, // Debug tag array output logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. output logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid, // Valid bits when accessing the Icache. One valid bit per way. F2 stage input logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, // Compare hits from Icache tags. Per way. F2 stage input logic ic_tag_perr, // Icache Tag parity error // ICCM ports output logic [pt.ICCM_BITS-1:1] iccm_rw_addr, // ICCM read/write address. output logic iccm_wren, // ICCM write enable (through the DMA) output logic iccm_rden, // ICCM read enable. output logic [ 77:0] iccm_wr_data, // ICCM write data. output logic [ 2:0] iccm_wr_size, // ICCM write location within DW. input logic [63:0] iccm_rd_data, // Data read from ICCM. input logic [77:0] iccm_rd_data_ecc, // Data + ECC read from ICCM. input logic [1:0] ifu_fetch_val, // IFU control signals output logic ic_hit_f, // Hit in Icache(if Icache access) or ICCM access( ICCM always has ic_hit_f) output logic [1:0] ic_access_fault_f, // Access fault (bus error or ICCM access in region but out of offset range). output logic [1:0] ic_access_fault_type_f, // Access fault types output logic iccm_rd_ecc_single_err, // This fetch has a single ICCM ECC error. output logic [1:0] iccm_rd_ecc_double_err, // This fetch has a double ICCM ECC error. output logic iccm_dma_rd_ecc_single_err, // This fetch has a single ICCM DMA ECC error. output logic iccm_dma_rd_ecc_double_err, // This fetch has a double ICCM DMA ECC error. output logic ic_error_start, // This has any I$ errors ( data/tag/ecc/parity ) output logic ifu_async_error_start, // Or of the sb iccm, and all the icache errors sent to aligner to stop output logic iccm_dma_sb_error, // Single Bit ECC error from a DMA access output logic [1:0] ic_fetch_val_f, // valid bytes for fetch. To the Aligner. output logic [31:0] ic_data_f, // Data read from Icache or ICCM. To the Aligner. output logic [63:0] ic_premux_data, // Premuxed data to be muxed with Icache data output logic ic_sel_premux_data, // Select premux data. ///// Debug // Icache/tag debug read/write packet input logic [70:0] icache_wrdata, input logic [16:0] icache_dicawics, input logic icache_rd_valid, input logic icache_wr_valid, input logic dec_tlu_core_ecc_disable, // disable the ecc checking and flagging output logic ifu_ic_debug_rd_data_valid, // debug data valid. output logic iccm_buf_correct_ecc, output logic iccm_correction_state, input logic ifu_pmp_error, input logic scan_mode ); el2_cache_debug_pkt_t dec_tlu_ic_diag_pkt; assign dec_tlu_ic_diag_pkt = {icache_wrdata, icache_dicawics, icache_rd_valid, icache_wr_valid}; el2_ifu_mem_ctl ifu_mem_ctl (.*); endmodule // el2_ifu_mem_ctl_wrapper ================================================ FILE: verification/block/ifu_mem_ctl/test_err.py ================================================ import cocotb from cocotb.triggers import ClockCycles, RisingEdge from common import ( get_bitflip_mask, initialize, rand_iccm_addr, rand_ifu_addr, read, reset, ) # Error states ERR_IDLE = 0b000 IC_WFF = 0b001 ECC_WFF = 0b010 ECC_CORR = 0b011 DMA_SB_ERR = 0b100 async def fetch_miss(dut, addr, req_bf_raw=1, uncacheable_bf=1): dut.ifc_fetch_req_bf.value = 1 dut.ifc_fetch_req_bf_raw.value = req_bf_raw dut.ifc_fetch_uncacheable_bf.value = uncacheable_bf dut.ifc_fetch_addr_bf.value = addr await RisingEdge(dut.clk) dut.ifc_fetch_req_bf_raw.value = 0 dut.ifc_fetch_uncacheable_bf.value = 0 dut.ifc_fetch_addr_bf.value = 0 def verify_state(dut, exp_state): state_names = [ "ERR_IDLE", "IC_WFF", "ECC_WFF", "ECC_CORR", "DMA_SB_ERR", ] assert ( dut.ifu_mem_ctl.perr_state.value == exp_state ), f"Expected state {state_names[exp_state]}, got {dut.ifu_mem_ctl.perr_state.value}" async def dma_sb_error(dut, force_halt=False): verify_state(dut, ERR_IDLE) dut.ifc_dma_access_ok.value = 1 dut.iccm_rd_data.value = 44 dut.iccm_rd_data_ecc.value = 44 ^ get_bitflip_mask(0) await fetch_miss(dut, rand_ifu_addr()) await read(dut, rand_iccm_addr()) await RisingEdge(dut.iccm_dma_rvalid) # dec_tlu_force_halt must appear here to achieve DMA_SB_ERR -> ERR_IDLE transition # FSM always switches state from `DMA_SB_ERR` in the next cycle if force_halt: dut.dec_tlu_force_halt.value = 1 await RisingEdge(dut.clk) verify_state(dut, DMA_SB_ERR) @cocotb.test() async def test_dma_sb_error(dut): await initialize(dut) verify_state(dut, ERR_IDLE) await dma_sb_error(dut) await reset(dut) verify_state(dut, ERR_IDLE) @cocotb.test() async def test_dma_sb_error_force_halt(dut): await initialize(dut) verify_state(dut, ERR_IDLE) await dma_sb_error(dut, force_halt=True) await ClockCycles(dut.clk, 1) verify_state(dut, ERR_IDLE) @cocotb.test() async def test_ecc_corr(dut): await initialize(dut) verify_state(dut, ERR_IDLE) await dma_sb_error(dut) await RisingEdge(dut.clk) verify_state(dut, ECC_CORR) await reset(dut) verify_state(dut, ERR_IDLE) async def ic_wff(dut): verify_state(dut, ERR_IDLE) dut.ic_tag_perr.value = 1 dut.ifc_dma_access_ok.value = 1 dut.iccm_rd_data.value = 44 dut.iccm_rd_data_ecc.value = 44 ^ get_bitflip_mask(1) await fetch_miss(dut, rand_ifu_addr()) await read(dut, rand_iccm_addr()) await RisingEdge(dut.clk) verify_state(dut, IC_WFF) @cocotb.test() async def test_ic_wff(dut): await initialize(dut) await ic_wff(dut) await reset(dut) verify_state(dut, ERR_IDLE) @cocotb.test() async def test_ic_wff_force_halt(dut): await initialize(dut) await ic_wff(dut) dut.dec_tlu_force_halt.value = 1 await ClockCycles(dut.clk, 2) verify_state(dut, ERR_IDLE) async def ecc_wff(dut): await initialize(dut) verify_state(dut, ERR_IDLE) dut.ic_tag_perr.value = 1 dut.ifc_dma_access_ok.value = 1 dut.ifc_iccm_access_bf.value = 1 dut.iccm_rd_data.value = 44 dut.iccm_rd_data_ecc.value = 44 await fetch_miss(dut, rand_ifu_addr()) await ClockCycles(dut.clk, 2) verify_state(dut, ECC_WFF) @cocotb.test() async def test_ecc_wff(dut): await initialize(dut) verify_state(dut, ERR_IDLE) await ecc_wff(dut) await reset(dut) verify_state(dut, ERR_IDLE) @cocotb.test() async def test_ecc_wff_force_halt(dut): await initialize(dut) await ecc_wff(dut) dut.dec_tlu_force_halt.value = 1 await ClockCycles(dut.clk, 2) verify_state(dut, ERR_IDLE) ================================================ FILE: verification/block/ifu_mem_ctl/test_err_stop.py ================================================ import cocotb from cocotb.triggers import ClockCycles, RisingEdge from common import initialize, rand_ifu_addr # Error stop states ERR_STOP_IDLE = 0b00 ERR_FETCH1 = 0b01 ERR_FETCH2 = 0b10 ERR_STOP_FETCH = 0b11 async def fetch_miss(dut, addr, req_bf_raw=1, uncacheable_bf=1): dut.ifc_fetch_req_bf.value = 1 dut.ifc_fetch_req_bf_raw.value = req_bf_raw dut.ifc_fetch_uncacheable_bf.value = uncacheable_bf dut.ifc_fetch_addr_bf.value = addr await RisingEdge(dut.clk) dut.ifc_fetch_req_bf_raw.value = 0 dut.ifc_fetch_uncacheable_bf.value = 0 dut.ifc_fetch_addr_bf.value = 0 def verify_state(dut, exp_state): state_names = [ "ERR_STOP_IDLE", "ERR_FETCH1", "ERR_FETCH2", "ERR_STOP_FETCH", ] assert ( dut.ifu_mem_ctl.err_stop_state.value == exp_state ), f"Expected state {state_names[exp_state]}, got {dut.ifu_mem_ctl.err_stop_state.value}" @cocotb.test() async def test_err_fetch1(dut): await initialize(dut) verify_state(dut, ERR_STOP_IDLE) # verify_state(dut, ERR_IDLE) dut.ic_tag_perr.value = 1 dut.ifc_dma_access_ok.value = 1 dut.ifc_iccm_access_bf.value = 1 dut.iccm_rd_data.value = 44 dut.iccm_rd_data_ecc.value = 44 await fetch_miss(dut, rand_ifu_addr()) await ClockCycles(dut.clk, 2) dut.dec_tlu_flush_err_wb.value = 1 # verify_state(dut, ECC_WFF) await ClockCycles(dut.clk, 2) verify_state(dut, ERR_FETCH1) @cocotb.test() async def test_err_fetch2(dut): await initialize(dut) verify_state(dut, ERR_STOP_IDLE) # verify_state(dut, ERR_IDLE) dut.ic_tag_perr.value = 1 dut.ifc_dma_access_ok.value = 1 dut.ifc_iccm_access_bf.value = 1 dut.ic_rd_data.value = 2**63 - 1 dut.iccm_rd_data.value = 44 dut.iccm_rd_data_ecc.value = 44 dut.ifu_fetch_val.value = 1 await fetch_miss(dut, rand_ifu_addr()) await ClockCycles(dut.clk, 2) dut.dec_tlu_flush_err_wb.value = 1 # verify_state(dut, ECC_WFF) await ClockCycles(dut.clk, 2) verify_state(dut, ERR_FETCH1) dut.ifu_fetch_val.value = 0 await ClockCycles(dut.clk, 1) verify_state(dut, ERR_FETCH2) await ClockCycles(dut.clk, 1) verify_state(dut, ERR_FETCH2) await ClockCycles(dut.clk, 5) dut.dec_tlu_force_halt.value = 1 await ClockCycles(dut.clk, 2) verify_state(dut, ERR_STOP_IDLE) # ERR_STOP_FETCH -> ERR_STOP_FETCH @cocotb.test() async def test_err_stop_fetch(dut): await initialize(dut) verify_state(dut, ERR_STOP_IDLE) # verify_state(dut, ERR_IDLE) dut.ic_tag_perr.value = 1 dut.ifc_dma_access_ok.value = 1 dut.ifc_iccm_access_bf.value = 1 dut.ic_rd_data.value = 2**63 - 1 dut.iccm_rd_data.value = 44 dut.iccm_rd_data_ecc.value = 44 dut.ifu_fetch_val.value = 1 await fetch_miss(dut, rand_ifu_addr()) await ClockCycles(dut.clk, 2) dut.dec_tlu_flush_err_wb.value = 1 # verify_state(dut, ECC_WFF) await ClockCycles(dut.clk, 2) verify_state(dut, ERR_FETCH1) await RisingEdge(dut.clk) verify_state(dut, ERR_FETCH2) dut.dec_tlu_flush_err_wb.value = 0 await RisingEdge(dut.clk) verify_state(dut, ERR_STOP_FETCH) await ClockCycles(dut.clk, 5) ================================================ FILE: verification/block/ifu_mem_ctl/test_miss.py ================================================ import cocotb from cocotb.triggers import ClockCycles, RisingEdge from common import ( initialize, rand_iccm_addr, rand_iccm_data, rand_ifu_addr, reset, write, ) # Miss states IDLE = 0b000 CRIT_BYP_OK = 0b001 HIT_U_MISS = 0b010 MISS_WAIT = 0b011 CRIT_WRD_RDY = 0b100 SCND_MISS = 0b101 STREAM = 0b110 STALL_SCND_MISS = 0b111 async def fetch_miss(dut, addr, req_bf_raw=1, uncacheable_bf=1, dma_access_ok=0): dut.ifc_fetch_req_bf.value = 1 dut.ifc_fetch_req_bf_raw.value = req_bf_raw dut.ifc_fetch_uncacheable_bf.value = uncacheable_bf dut.ifc_fetch_addr_bf.value = addr dut.ifc_dma_access_ok.value = dma_access_ok await RisingEdge(dut.clk) dut.ifc_fetch_req_bf.value = 0 dut.ifc_fetch_req_bf_raw.value = 0 dut.ifc_fetch_uncacheable_bf.value = 0 dut.ifc_fetch_addr_bf.value = 0 dut.ifc_dma_access_ok.value = 0 def verify_state(dut, exp_state): state_names = [ "IDLE", "CRIT_BYP_OK", "HIT_U_MISS", "MISS_WAIT", "CRIT_WRD_RDY", "SCND_MISS", "STREAM", "STALL_SCND_MISS", ] assert ( dut.ifu_mem_ctl.miss_state.value == exp_state ), f"Expected state {state_names[exp_state]}, got {dut.ifu_mem_ctl.miss_state.value}" async def crit_byp_ok(dut): verify_state(dut, IDLE) await fetch_miss(dut, 128, dma_access_ok=1) await write(dut, rand_iccm_addr(), rand_iccm_data()) await RisingEdge(dut.clk) verify_state(dut, CRIT_BYP_OK) @cocotb.test() async def test_crit_byp_ok(dut): await initialize(dut) await crit_byp_ok(dut) await reset(dut) verify_state(dut, IDLE) @cocotb.test() async def test_crit_byp_ok_force_halt(dut): await initialize(dut) await crit_byp_ok(dut) dut.dec_tlu_force_halt.value = 1 await ClockCycles(dut.clk, 2) verify_state(dut, IDLE) async def crit_wrd_rdy(dut): verify_state(dut, IDLE) await fetch_miss(dut, rand_ifu_addr()) await write(dut, rand_iccm_addr(), rand_iccm_data()) await RisingEdge(dut.clk) verify_state(dut, CRIT_BYP_OK) await write(dut, rand_iccm_addr(), rand_iccm_data()) await ClockCycles(dut.clk, 2) verify_state(dut, CRIT_WRD_RDY) @cocotb.test() async def test_crit_wrd_rdy(dut): await initialize(dut) await crit_wrd_rdy(dut) await reset(dut) verify_state(dut, IDLE) @cocotb.test() async def test_crit_wrd_rdy_force_halt(dut): await initialize(dut) await crit_wrd_rdy(dut) dut.dec_tlu_force_halt.value = 1 await ClockCycles(dut.clk, 2) verify_state(dut, IDLE) async def hit_u_miss(dut): verify_state(dut, IDLE) await fetch_miss(dut, rand_ifu_addr(), req_bf_raw=0, dma_access_ok=1) await write(dut, rand_iccm_addr(), rand_iccm_data()) await ClockCycles(cocotb.top.clk, 1) verify_state(dut, CRIT_BYP_OK) dut.exu_flush_final.value = 1 await ClockCycles(cocotb.top.clk, 2) verify_state(dut, HIT_U_MISS) dut.exu_flush_final.value = 0 @cocotb.test() async def test_hit_u_miss(dut): await initialize(dut) await hit_u_miss(dut) await reset(dut) verify_state(dut, IDLE) @cocotb.test() async def test_hit_u_miss_force_halt(dut): await initialize(dut) await hit_u_miss(dut) dut.dec_tlu_force_halt.value = 1 await ClockCycles(dut.clk, 2) verify_state(dut, IDLE) async def scnd_miss(dut): verify_state(dut, IDLE) await hit_u_miss(dut) await fetch_miss(dut, rand_ifu_addr(), req_bf_raw=0, dma_access_ok=1) await write(dut, rand_iccm_addr(), rand_iccm_data()) await RisingEdge(dut.clk) verify_state(dut, SCND_MISS) @cocotb.test() async def test_scnd_miss(dut): await initialize(dut) await scnd_miss(dut) await reset(dut) verify_state(dut, IDLE) @cocotb.test() async def test_scnd_miss_force_halt(dut): await initialize(dut) await scnd_miss(dut) dut.dec_tlu_force_halt.value = 1 await ClockCycles(dut.clk, 2) verify_state(dut, IDLE) async def stall_scnd_miss(dut): verify_state(dut, IDLE) await hit_u_miss(dut) await fetch_miss(dut, 0, req_bf_raw=0) await write(dut, rand_iccm_addr(), rand_iccm_data()) await ClockCycles(dut.clk, 1) verify_state(dut, STALL_SCND_MISS) @cocotb.test() async def test_stall_scnd_miss(dut): await initialize(dut) await stall_scnd_miss(dut) await reset(dut) verify_state(dut, IDLE) @cocotb.test() async def test_stall_scnd_miss_force_halt(dut): await initialize(dut) await stall_scnd_miss(dut) dut.dec_tlu_force_halt.value = 1 await ClockCycles(dut.clk, 2) verify_state(dut, IDLE) ================================================ FILE: verification/block/lib_ahb_to_axi4/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = ahb_to_axi4_wrapper VERILOG_SOURCES = \ $(SRCDIR)/lib/ahb_to_axi4.sv \ $(TEST_DIR)/ahb_to_axi4_wrapper.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/lib_ahb_to_axi4/ahb_to_axi4_wrapper.sv ================================================ module ahb_to_axi4_wrapper #( TAG = 1, `include "el2_param.vh" ) ( input clk, input rst_l, input scan_mode, input bus_clk_en, input clk_override, output logic axi_awvalid, input logic axi_awready, output logic [TAG-1:0] axi_awid, output logic [31:0] axi_awaddr, output logic [2:0] axi_awsize, output logic [2:0] axi_awprot, output logic [7:0] axi_awlen, output logic [1:0] axi_awburst, output logic axi_wvalid, input logic axi_wready, output logic [63:0] axi_wdata, output logic [7:0] axi_wstrb, output logic axi_wlast, input logic axi_bvalid, output logic axi_bready, input logic [1:0] axi_bresp, input logic [TAG-1:0] axi_bid, output logic axi_arvalid, input logic axi_arready, output logic [TAG-1:0] axi_arid, output logic [31:0] axi_araddr, output logic [2:0] axi_arsize, output logic [2:0] axi_arprot, output logic [7:0] axi_arlen, output logic [1:0] axi_arburst, input logic axi_rvalid, output logic axi_rready, input logic [TAG-1:0] axi_rid, input logic [63:0] axi_rdata, input logic [1:0] axi_rresp, input logic [31:0] ahb_haddr, input logic [2:0] ahb_hburst, input logic ahb_hmastlock, input logic [3:0] ahb_hprot, input logic [2:0] ahb_hsize, input logic [1:0] ahb_htrans, input logic ahb_hwrite, input logic [63:0] ahb_hwdata, input logic ahb_hsel, input logic ahb_hreadyin, output logic [63:0] ahb_hrdata, output logic ahb_hreadyout, output logic ahb_hresp ); // set CHECK_RANGES(0), the rest remains default. // this allows working with the full range of addresses. ahb_to_axi4 #(.pt(pt),.CHECK_RANGES(0)) inst ( .* ); endmodule // ahb_to_axi4_wrapper ================================================ FILE: verification/block/lib_ahb_to_axi4/test_read.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles, Combine from pyuvm import * from testbench import ( AXI4LiteReadyItem, AXI4LiteResponseItem, BaseEnv, BaseTest, BusReadItem, ) # ============================================================================= class AHBReadSequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): align = 8 addr = align * random.randint(0, 0x1FFFFFFF) item = BusReadItem(addr) await self.start_item(item) await self.finish_item(item) class AXI4LiteReadResponseSequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Respond to AR item = AXI4LiteResponseItem(["ar"]) await self.start_item(item) await self.finish_item(item) # Emulate latency await ClockCycles(cocotb.top.clk, 2) # Respond on R item = AXI4LiteResponseItem(["r"]) await self.start_item(item) await self.finish_item(item) class AXI4LiteNoReadDataResponseSequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Respond to AR but not to R item = AXI4LiteResponseItem(["ar"]) await self.start_item(item) await self.finish_item(item) # ============================================================================= class AXI4LiteReadReadySequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Become ready item = AXI4LiteReadyItem(["ar"], True) await self.start_item(item) await self.finish_item(item) # ============================================================================= async def later(cr, cycles): """ A helper function to start a task after a number of clock cycles """ await ClockCycles(cocotb.top.clk, cycles) await cr class NoBackpressureReadSequence(uvm_sequence): async def body(self): ahb_seqr = ConfigDB().get(None, "", "AHB_SEQR") axi_seqr = ConfigDB().get(None, "", "AXI_SEQR") axi_rdy = AXI4LiteReadReadySequence("ready") ahb_seq = AHBReadSequence("stimulus") axi_seq = AXI4LiteReadResponseSequence("response") # Issue an AHB read and do a correct AXI response await axi_rdy.start(axi_seqr) tasks = [ cocotb.start_soon(ahb_seq.start(ahb_seqr)), cocotb.start_soon(axi_seq.start(axi_seqr)), ] await Combine(*tasks) class BackpressureReadSequence(uvm_sequence): async def body(self): ahb_seqr = ConfigDB().get(None, "", "AHB_SEQR") axi_seqr = ConfigDB().get(None, "", "AXI_SEQR") ahb_seq = AHBReadSequence("stimulus") axi_seq = AXI4LiteReadResponseSequence("response") # Issue an AHB read and do a correct AXI response tasks = [ cocotb.start_soon(ahb_seq.start(ahb_seqr)), cocotb.start_soon(later(axi_seq.start(axi_seqr), 5)), ] await Combine(*tasks) class NoReadDataResponseSequence(uvm_sequence): async def body(self): ahb_seqr = ConfigDB().get(None, "", "AHB_SEQR") axi_seqr = ConfigDB().get(None, "", "AXI_SEQR") axi_rdy = AXI4LiteReadReadySequence("ready") ahb_seq = AHBReadSequence("stimulus") axi_seq = AXI4LiteNoReadDataResponseSequence("response") # Issue an AHB read and do a correct AXI response await axi_rdy.start(axi_seqr) tasks = [ cocotb.start_soon(ahb_seq.start(ahb_seqr)), cocotb.start_soon(axi_seq.start(axi_seqr)), ] await Combine(*tasks) # ============================================================================= @pyuvm.test() class TestReadNoBackpressure(BaseTest): """ Read test with no AXI backpressure """ def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = NoBackpressureReadSequence() async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for i in range(count): await self.seq.start() await ClockCycles(cocotb.top.clk, gap) @pyuvm.test() class TestReadBackpressure(BaseTest): """ Read test with AXI backpressure """ def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BackpressureReadSequence() async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for i in range(count): await self.seq.start() await ClockCycles(cocotb.top.clk, gap) @pyuvm.test(expect_error=TimeoutError) class TestReadNoDataResponse(BaseTest): """ Read test with response on AR channel but not on R channel. A timeout should occur due to lack of the response. """ def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = NoReadDataResponseSequence() async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for i in range(count): await self.seq.start() await ClockCycles(cocotb.top.clk, gap) ================================================ FILE: verification/block/lib_ahb_to_axi4/test_write.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import ( AXI4LiteReadyItem, AXI4LiteResponseItem, BaseEnv, BaseTest, BusWriteItem, ) # ============================================================================= class AHBWriteSequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): dwidth = 64 align = 8 addr = align * random.randint(0, 0x1FFFFFFF) data = [random.randrange(0, (1 << dwidth) - 1)] item = BusWriteItem(addr, data) await self.start_item(item) await self.finish_item(item) class AXI4LiteWriteResponseSequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Respond to AW and W item = AXI4LiteResponseItem(["aw", "w"]) await self.start_item(item) await self.finish_item(item) # Emulate latency await ClockCycles(cocotb.top.clk, 2) # Respond on B item = AXI4LiteResponseItem(["b"]) await self.start_item(item) await self.finish_item(item) class AXI4LiteNoWriteDataResponseSequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Respond to AW only item = AXI4LiteResponseItem(["aw"]) await self.start_item(item) await self.finish_item(item) # Emulate latency await ClockCycles(cocotb.top.clk, 2) # Respond on B item = AXI4LiteResponseItem(["b"]) await self.start_item(item) await self.finish_item(item) class AXI4LiteNoWriteAddrResponseSequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Respond to W only item = AXI4LiteResponseItem(["w"]) await self.start_item(item) await self.finish_item(item) # Emulate latency await ClockCycles(cocotb.top.clk, 2) # Respond on B item = AXI4LiteResponseItem(["b"]) await self.start_item(item) await self.finish_item(item) class AXI4LiteNoWriteResponseSequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Respond to AW and W, do NOT respond to B item = AXI4LiteResponseItem(["aw", "w"]) await self.start_item(item) await self.finish_item(item) # ============================================================================= class AXI4LiteWriteReadySequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Become ready item = AXI4LiteReadyItem(["aw", "w"], True) await self.start_item(item) await self.finish_item(item) class AXI4LiteNoWriteDataReadySequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Become ready item = AXI4LiteReadyItem(["aw"], True) await self.start_item(item) await self.finish_item(item) class AXI4LiteNoWriteAddrReadySequence(uvm_sequence): def __init__(self, name): super().__init__(name) async def body(self): # Become ready item = AXI4LiteReadyItem(["w"], True) await self.start_item(item) await self.finish_item(item) # ============================================================================= class NoBackpressureWriteSequence(uvm_sequence): async def body(self): ahb_seqr = ConfigDB().get(None, "", "AHB_SEQR") axi_seqr = ConfigDB().get(None, "", "AXI_SEQR") axi_rdy = AXI4LiteWriteReadySequence("ready") ahb_seq = AHBWriteSequence("stimulus") axi_seq = AXI4LiteWriteResponseSequence("response") # Issue an AHB write and do a correct AXI response await axi_rdy.start(axi_seqr) await ahb_seq.start(ahb_seqr) await axi_seq.start(axi_seqr) class BackpressureWriteSequence(uvm_sequence): async def body(self): ahb_seqr = ConfigDB().get(None, "", "AHB_SEQR") axi_seqr = ConfigDB().get(None, "", "AXI_SEQR") ahb_seq = AHBWriteSequence("stimulus") axi_seq = AXI4LiteWriteResponseSequence("response") # Issue an AHB write and do a correct AXI response await ahb_seq.start(ahb_seqr) await axi_seq.start(axi_seqr) class NoWriteResponseSequence(uvm_sequence): async def body(self): ahb_seqr = ConfigDB().get(None, "", "AHB_SEQR") axi_seqr = ConfigDB().get(None, "", "AXI_SEQR") axi_rdy = AXI4LiteWriteReadySequence("ready") ahb_seq = AHBWriteSequence("stimulus") axi_seq = AXI4LiteNoWriteResponseSequence("response") await axi_rdy.start(axi_seqr) await ahb_seq.start(ahb_seqr) await axi_seq.start(axi_seqr) class NoWriteDataResponseSequence(uvm_sequence): async def body(self): ahb_seqr = ConfigDB().get(None, "", "AHB_SEQR") axi_seqr = ConfigDB().get(None, "", "AXI_SEQR") axi_rdy = AXI4LiteNoWriteDataReadySequence("ready") ahb_seq = AHBWriteSequence("stimulus") axi_seq = AXI4LiteNoWriteDataResponseSequence("response") await axi_rdy.start(axi_seqr) await ahb_seq.start(ahb_seqr) await axi_seq.start(axi_seqr) class NoWriteAddrResponseSequence(uvm_sequence): async def body(self): ahb_seqr = ConfigDB().get(None, "", "AHB_SEQR") axi_seqr = ConfigDB().get(None, "", "AXI_SEQR") axi_rdy = AXI4LiteNoWriteAddrReadySequence("ready") ahb_seq = AHBWriteSequence("stimulus") axi_seq = AXI4LiteNoWriteAddrResponseSequence("response") await axi_rdy.start(axi_seqr) await ahb_seq.start(ahb_seqr) await axi_seq.start(axi_seqr) # ============================================================================= @pyuvm.test() class TestWriteNoBackpressure(BaseTest): """ Write test with no AXI backpressure """ def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = NoBackpressureWriteSequence() async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for i in range(count): await self.seq.start() await ClockCycles(cocotb.top.clk, gap) @pyuvm.test() class TestWriteBackpressure(BaseTest): """ Write test with AXI backpressure """ def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = BackpressureWriteSequence() async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for i in range(count): await self.seq.start() await ClockCycles(cocotb.top.clk, gap) # FIXME: This test is expected to fail as the AHB to AXI bridge does not wait # for response on B channel and completely ignores it @pyuvm.test(expect_fail=True) # FIXME: should be expect_fail=False class TestWriteNoResponse(BaseTest): """ Write test with no AXI backpressure but without a response on B channel """ def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = NoWriteResponseSequence() async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for i in range(count): await self.seq.start() await ClockCycles(cocotb.top.clk, gap) @pyuvm.test(expect_error=TimeoutError) class TestWriteNoAddrResponse(BaseTest): """ Write test with no AXI backpressure and no response on AW. A timeout should occur due to lack of the response. """ def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = NoWriteAddrResponseSequence() async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for i in range(count): await self.seq.start() await ClockCycles(cocotb.top.clk, gap) # FIXME: The module ignores wready and does not wait until data gets accepted # by the subordinate. @pyuvm.test(expect_fail=True) # FIXME: should be expect_error=Timeout class TestWriteNoDataResponse(BaseTest): """ Write test with no AXI backpressure and no response on W. A timeout should occur due to lack of the response. """ def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = NoWriteDataResponseSequence() async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") gap = ConfigDB().get(None, "", "TEST_BURST_GAP") for i in range(count): await self.seq.start() await ClockCycles(cocotb.top.clk, gap) ================================================ FILE: verification/block/lib_ahb_to_axi4/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import os import random import sys from enum import Enum import pyuvm from axi import Axi4LiteMonitor, BusReadItem, BusWriteItem from cocotb.clock import Clock from cocotb.triggers import ClockCycles, Combine, FallingEdge, RisingEdge from pyuvm import * from utils import collect_bytes, collect_signals # ============================================================================== class AXI4LiteReadyItem(uvm_sequence_item): """ An item describing ready signal assertion / deassertion for an AXI4 lite channel(s) """ def __init__(self, channels, ready=True): super().__init__("AXI4LiteReadyItem") self.channels = channels self.ready = ready class AXI4LiteResponseItem(uvm_sequence_item): """ An item describing a response for an AXI4 lite channel(s) """ def __init__(self, channels): super().__init__("AXI4LiteResponseItem") self.channels = channels # ============================================================================== class AHBLiteManagerBFM(uvm_component): """ AHB Lite bus BFM that operates as a manager. """ SIGNALS = [ "hclk", "hreset", "haddr", "hburst", "hmastlock", "hprot", "hsize", "htrans", "hwrite", "hwdata", "hsel", "hrdata", "hreadyout", "hresp", ] class HTRANS(Enum): IDLE = 0b00 BUSY = 0b01 NONSEQ = 0b10 SEQ = 0b11 class HBURST(Enum): SINGLE = 0b000 INCR = 0b001 WRAP4 = 0b010 INCR4 = 0b011 WRAP8 = 0b100 INCR8 = 0b101 WRAP16 = 0b110 INCR16 = 0b111 def __init__(self, name, parent, uut, signal_prefix="", signal_map=None): super().__init__(name, parent) collect_signals( self.SIGNALS, uut, self, uut_prefix=signal_prefix, obj_prefix="ahb_", signal_map=signal_map, ) # Determine bus parameters self.awidth = len(self.ahb_haddr) self.dwidth = len(self.ahb_hwdata) # Assuming hrdata is the same # Calculate HSIZE encoding self.hsize = { 64 // self.dwidth: 3, 128 // self.dwidth: 4, 256 // self.dwidth: 5, 512 // self.dwidth: 6, 1024 // self.dwidth: 7, } self.logger.debug("AHB Lite manager BFM:") self.logger.debug(" awidth = {}".format(self.awidth)) self.logger.debug(" dwidth = {}".format(self.dwidth)) async def _wait(self, signal, max_cycles=200): """ Waits for a signal to be asserted for at most max_cycles. Raises an exception if it does not """ for i in range(max_cycles): await RisingEdge(self.ahb_hclk) if signal.value == 1: break else: raise TimeoutError("{} timeout".format(str(signal))) async def write(self, addr, data): """ Issues a write transfer. Parameter data must be a list of integers where each one represents a full bus data word. The word count must be one of multiplies of data bus width supported by AHB Lite. """ lnt = len(data) assert lnt in self.hsize # Wait for reset deassertion if necessary if self.ahb_hreset.value == 0: await RisingEdge(self.ahb_hreset) # Address phase await RisingEdge(self.ahb_hclk) self.ahb_hsel.value = 1 self.ahb_hprot.value = 1 # Indicates a data transfer self.ahb_hsize.value = self.hsize[lnt] self.ahb_haddr.value = addr self.ahb_hwrite.value = 1 self.ahb_htrans.value = self.HTRANS.NONSEQ.value self.ahb_hburst.value = self.HBURST.SINGLE.value await self._wait(self.ahb_hreadyout) # Data phase for i, word in enumerate(data): if i != lnt - 1: addr += self.dwidth // 8 self.ahb_haddr.value = addr self.ahb_htrans.value = self.HTRANS.SEQ.value else: self.ahb_htrans.value = self.HTRANS.IDLE.value self.ahb_hwdata.value = word await self._wait(self.ahb_hreadyout) async def read(self, addr, length): """ Issues an AHB read transfer for the given number of bus data words. The word count must be one of multiplies of data bus width supported by AHB Lite. """ assert length in self.hsize # Wait for reset deassertion if necessary if self.ahb_hreset.value == 0: await RisingEdge(self.ahb_hreset) # Address phase await RisingEdge(self.ahb_hclk) self.ahb_hsel.value = 1 self.ahb_hprot.value = 1 # Data self.ahb_hsize.value = self.hsize[length] self.ahb_haddr.value = addr self.ahb_hwrite.value = 0 self.ahb_htrans.value = self.HTRANS.NONSEQ.value self.ahb_hburst.value = self.HBURST.SINGLE.value await self._wait(self.ahb_hreadyout) # Data phase for i in range(length): if i != length - 1: addr += self.dwidth // 8 self.ahb_haddr.value = addr self.ahb_htrans.value = self.HTRANS.SEQ.value else: self.ahb_htrans.value = self.HTRANS.IDLE.value await self._wait(self.ahb_hreadyout) class AHBLiteManagerDriver(uvm_driver): """ A driver for AHB Lite BFM """ def __init__(self, *args, **kwargs): self.bfm = kwargs["bfm"] del kwargs["bfm"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, BusWriteItem): await self.bfm.write(it.addr, it.data) elif isinstance(it, BusReadItem): # TODO: Since the intended UUT does not support burst transfers # here we are reading only a single data word. await self.bfm.read(it.addr, 1) else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class AHBLiteMonitor(uvm_component): """ AHB Lite bus monitor """ def __init__(self, *args, **kwargs): self.bfm = kwargs["bfm"] del kwargs["bfm"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def watch(self): """ Watches the bus """ data_stage = False hdata = bytearray() haddr = None htrans = None hwrite = None await RisingEdge(self.bfm.ahb_hreset) while True: # Wait for reset deassertion if necessary if self.bfm.ahb_hreset.value == 0: await RisingEdge(self.bfm.ahb_hreset) # Wait for clock edge and hready await RisingEdge(self.bfm.ahb_hclk) hready = int(self.bfm.ahb_hreadyout) if hready: # Sample data if data_stage: if htrans in [AHBLiteManagerBFM.HTRANS.SEQ, AHBLiteManagerBFM.HTRANS.NONSEQ]: if hwrite: data = collect_bytes(self.bfm.ahb_hwdata) else: data = collect_bytes(self.bfm.ahb_hrdata) hdata += data # Transfer end elif htrans == AHBLiteManagerBFM.HTRANS.IDLE: self.logger.debug( "{}: 0x{:08X} {}".format( "WR" if hwrite else "RD", haddr, ["0x{:02X}".format(b) for b in hdata], ) ) data_stage = False # Send response if hwrite: cls = BusWriteItem else: cls = BusReadItem self.ap.write(cls(haddr, hdata)) # Sample bus signals htrans = AHBLiteManagerBFM.HTRANS(self.bfm.ahb_htrans.value) if not data_stage: if htrans in [AHBLiteManagerBFM.HTRANS.SEQ, AHBLiteManagerBFM.HTRANS.NONSEQ]: hwrite = int(self.bfm.ahb_hwrite.value) haddr = int(self.bfm.ahb_haddr.value) hdata = bytearray() data_stage = True async def run_phase(self): cocotb.start_soon(self.watch()) # ============================================================================== class AXI4LiteSubordinateBFM(uvm_component): """ AXI 4 Lite subordinate BFM. Allows low-level per-channel acknowledgement control. """ SIGNALS = [ "clk", "rst", "awvalid", "awready", "awid", "awaddr", "awsize", "wvalid", "wready", "wdata", "wstrb", "bvalid", "bready", "bresp", "bid", "arvalid", "arready", "arid", "araddr", "arsize", "rvalid", "rready", "rid", "rdata", "rresp", ] def __init__(self, name, parent, uut, signal_prefix="", signal_map=None): super().__init__(name, parent) # Collect signals collect_signals( self.SIGNALS, uut, self, uut_prefix=signal_prefix, obj_prefix="axi_", signal_map=signal_map, ) # Determine bus parameters self.awidth = len(self.axi_awaddr) self.dwidth = len(self.axi_wdata) self.swidth = len(self.axi_wstrb) assert self.swidth == (self.dwidth // 8) self.logger.debug("AXI4 Lite BFM:") self.logger.debug(" awidth = {}".format(self.awidth)) self.logger.debug(" dwidth = {}".format(self.dwidth)) self.logger.debug(" swidth = {}".format(self.swidth)) self.axi_awready.value = 0 self.axi_wready.value = 0 self.axi_arready.value = 0 self.axi_rvalid.value = 0 async def _wait(self, signal, max_cycles=200): """ Waits for a signal to be asserted for at most max_cycles. Raises an exception if it does not """ for i in range(max_cycles): await RisingEdge(self.axi_clk) if signal.value != 0: break else: raise TimeoutError("{} timeout".format(str(signal))) async def set_ready(self, channel, ready): """ Sets/clears ready signal for the given channel on next clock edge """ assert channel in ["aw", "w", "ar", "r"], channel await RisingEdge(self.axi_clk) sig = "axi_{}ready".format(channel) sig = getattr(self, sig) sig.value = int(ready) async def respond_aw(self): self.axi_awready.value = 1 await self._wait(self.axi_awvalid) self.axi_awready.value = 0 async def respond_w(self): self.axi_wready.value = 1 for i in range(1): await self._wait(self.axi_wvalid) self.axi_wready.value = 0 async def respond_b(self): await self._wait(self.axi_bready) self.axi_bvalid.value = 1 self.axi_bid.value = 0 # TODO: support providing different BID values self.axi_bresp.value = 0 # TODO: support providing different BRESP values await RisingEdge(self.axi_clk) self.axi_bvalid.value = 0 async def respond_ar(self): self.axi_arready.value = 1 await self._wait(self.axi_arvalid) self.axi_arready.value = 0 async def respond_r(self): await self._wait(self.axi_rready) self.axi_rvalid.value = 1 self.axi_rdata.value = random.randrange(0, (1 << self.dwidth) - 1) await RisingEdge(self.axi_clk) self.axi_rvalid.value = 0 class AXI4LiteSubordinateDriver(uvm_driver): """ PyUVM driver for AXI 4 Lite subordinate BFM """ def __init__(self, *args, **kwargs): self.bfm = kwargs["bfm"] del kwargs["bfm"] super().__init__(*args, **kwargs) async def run_phase(self): func_map = { "aw": self.bfm.respond_aw, "w": self.bfm.respond_w, "b": self.bfm.respond_b, "ar": self.bfm.respond_ar, "r": self.bfm.respond_r, } while True: it = await self.seq_item_port.get_next_item() if isinstance(it, AXI4LiteResponseItem): tasks = [cocotb.start_soon(func_map[c]()) for c in it.channels] await Combine(*tasks) elif isinstance(it, AXI4LiteReadyItem): tasks = [cocotb.start_soon(self.bfm.set_ready(c, it.ready)) for c in it.channels] await Combine(*tasks) else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() # ============================================================================== class Scoreboard(uvm_component): """ A scoreboard that compares AHB and AXI transfers and checks if they refer to the same address and contain the same data. """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.ahb_fifo = uvm_tlm_analysis_fifo("ahb_fifo", self) self.ahb_port = uvm_get_port("ahb_port", self) self.axi_fifo = uvm_tlm_analysis_fifo("axi_fifo", self) self.axi_port = uvm_get_port("axi_port", self) def connect_phase(self): self.ahb_port.connect(self.ahb_fifo.get_export) self.axi_port.connect(self.axi_fifo.get_export) def check_phase(self): # Check transactions while self.ahb_port.can_get() and self.axi_port.can_get(): self.passed = True # Get items _, ahb_item = self.ahb_port.try_get() _, axi_item = self.axi_port.try_get() # Check msg = "AHB: {} A:0x{:08X} D:[{}], ".format( type(ahb_item).__name__, ahb_item.addr, ",".join(["0x{:02X}".format(d) for d in ahb_item.data]), ) msg += "AXI: {} A:0x{:08X} D:[{}]".format( type(ahb_item).__name__, axi_item.addr, ",".join(["0x{:02X}".format(d) for d in axi_item.data]), ) if ahb_item.addr != axi_item.addr or ahb_item.data != axi_item.data: self.logger.error(msg) self.passed = False else: self.logger.debug(msg) # Indicate an error if there is any leftover transaction in any of the # queues. if self.ahb_port.can_get() or self.axi_port.can_get(): self.logger.error("Spurious transaction(s) on one of the buses") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 50) ConfigDB().set(None, "*", "TEST_BURST_LEN", 10) ConfigDB().set(None, "*", "TEST_BURST_GAP", 10) # Sequencers self.ahb_seqr = uvm_sequencer("ahb_seqr", self) self.axi_seqr = uvm_sequencer("axi_seqr", self) ConfigDB().set(None, "*", "AHB_SEQR", self.ahb_seqr) ConfigDB().set(None, "*", "AXI_SEQR", self.axi_seqr) # BFM self.ahb_bfm = AHBLiteManagerBFM( "ahb_bfm", self, uut=cocotb.top, signal_prefix="ahb_", signal_map={ "hclk": "clk", "hreset": "rst_l", }, ) self.axi_bfm = AXI4LiteSubordinateBFM( "axi_bfm", self, uut=cocotb.top, signal_prefix="axi_", signal_map={ "clk": "clk", "rst": "rst_l", }, ) # Driver self.ahb_drv = AHBLiteManagerDriver("ahb_drv", self, bfm=self.ahb_bfm) self.axi_drv = AXI4LiteSubordinateDriver("axi_drv", self, bfm=self.axi_bfm) # Monitor self.ahb_mon = AHBLiteMonitor("ahb_mon", self, bfm=self.ahb_bfm) self.axi_mon = Axi4LiteMonitor("axi_mon", self, bfm=self.axi_bfm) # Scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): self.ahb_drv.seq_item_port.connect(self.ahb_seqr.seq_item_export) self.axi_drv.seq_item_port.connect(self.axi_seqr.seq_item_export) self.ahb_mon.ap.connect(self.scoreboard.ahb_fifo.analysis_export) self.axi_mon.ap.connect(self.scoreboard.axi_fifo.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.scan_mode.value = 0 cocotb.top.clk_override.value = 0 cocotb.top.axi_awready.value = 0 cocotb.top.axi_wready.value = 0 cocotb.top.axi_bvalid.value = 0 cocotb.top.axi_bresp.value = 0 cocotb.top.axi_bid.value = 0 cocotb.top.axi_arready.value = 0 cocotb.top.axi_rvalid.value = 0 cocotb.top.axi_rid.value = 0 cocotb.top.axi_rdata.value = 0 cocotb.top.axi_rresp.value = 0 cocotb.top.ahb_haddr.value = 0 cocotb.top.ahb_hburst.value = 0 cocotb.top.ahb_hmastlock.value = 0 cocotb.top.ahb_hprot.value = 0 cocotb.top.ahb_hsize.value = 0 cocotb.top.ahb_htrans.value = 0 cocotb.top.ahb_hwrite.value = 0 cocotb.top.ahb_hwdata.value = 0 cocotb.top.ahb_hsel.value = 0 cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() # Set common DUT signals cocotb.top.bus_clk_en.value = 1 cocotb.top.ahb_hreadyin.value = 1 # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/lib_ahb_to_axi4/ucli.key ================================================ ================================================ FILE: verification/block/lib_axi4_to_ahb/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = axi4_to_ahb CM_FILE = cm.cfg VERILOG_SOURCES = \ $(SRCDIR)/lib/axi4_to_ahb.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/lib_axi4_to_ahb/ahb_lite_agent.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import cocotb from ahb_lite_bfm import AHBLiteBFM from cocotb.queue import QueueEmpty from cocotb.triggers import RisingEdge from pyuvm import ConfigDB, uvm_agent, uvm_analysis_port, uvm_driver, uvm_sequencer from common import BaseMonitor, get_int class AHBLiteAgent(uvm_agent): """ Seqr <---> Driver Monitor <--^ """ def build_phase(self): self.seqr = uvm_sequencer("seqr", self) ConfigDB().set(None, "*", "ahb_seqr", self.seqr) self.monitor = AHBLiteMonitor("axi_w_agent", self) self.driver = AHBLiteDriver("axi_w_driver", self) def connect_phase(self): self.driver.seq_item_port.connect(self.seqr.seq_item_export) class AHBLiteDriver(uvm_driver): def build_phase(self): self.ap = uvm_analysis_port("ap", self) self.rst_n = cocotb.top.rst_l self.clk = cocotb.top.clk def start_of_simulation_phase(self): self.bfm = AHBLiteBFM() async def run_phase(self): self.bfm.start_bfm() while True: if get_int(self.rst_n) == 0: await RisingEdge(self.rst_n) self.logger.info("Agent: AHB Lite: Reset Posedge") await RisingEdge(self.clk) try: response = self.bfm.rsp_driver_q.get_nowait() self.seq_item_port.put_response(response) # Expect two items per one response (hready is asserted for 2 cycles) for _ in range(2): item = await self.seq_item_port.get_next_item() await self.drive(item) self.logger.debug(f"Driven: {item}") self.seq_item_port.item_done() except QueueEmpty: pass async def drive(self, item): await self.bfm.req_driver_q_put( item.ahb_hrdata, item.ahb_hready, item.ahb_hresp, ) class AHBLiteMonitor(BaseMonitor): def __init__(self, name, parent): super().__init__(name, parent) def build_phase(self): super().build_phase() self.bfm = AHBLiteBFM() ================================================ FILE: verification/block/lib_axi4_to_ahb/ahb_lite_bfm.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import cocotb from ahb_lite_pkg import ( AHB_LITE_NOTIFICATION, AHB_LITE_RESPONSE_CODES, AHB_LITE_TRANSFER_TYPE_ENCODING, AHB_RSP_SIGNALS, ) from cocotb.queue import QueueEmpty from cocotb.triggers import RisingEdge from pyuvm import UVMQueue, utility_classes from common import get_int, get_signals class AHBLiteBFM(metaclass=utility_classes.Singleton): def __init__(self): self.dut = cocotb.top self.rst_n = cocotb.top.rst_l self.clk = cocotb.top.clk self.req_driver_q = UVMQueue(maxsize=1) self.rsp_driver_q = UVMQueue() self.req_monitor_q = UVMQueue() self.rsp_monitor_q = UVMQueue() async def req_driver_q_put(self, ahb_hrdata, ahb_hready, ahb_hresp): item = (ahb_hrdata, ahb_hready, ahb_hresp) await self.req_driver_q.put(item) async def req_monitor_q_get(self): item = await self.req_monitor_q.get() return item async def rsp_monitor_q_get(self): result = await self.rsp_monitor_q.get() return result async def drive(self): prev_htrans = AHB_LITE_TRANSFER_TYPE_ENCODING.IDLE htrans = AHB_LITE_TRANSFER_TYPE_ENCODING.IDLE await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: self.dut.ahb_hrdata.value = 0 self.dut.ahb_hready.value = 0 self.dut.ahb_hresp.value = 0 await RisingEdge(self.rst_n) await RisingEdge(self.clk) prev_htrans = htrans if get_int(self.dut.ahb_htrans) == AHB_LITE_TRANSFER_TYPE_ENCODING.IDLE: htrans = AHB_LITE_TRANSFER_TYPE_ENCODING.IDLE self.dut.ahb_hrdata.value = 0 self.dut.ahb_hready.value = 0 self.dut.ahb_hresp.value = AHB_LITE_RESPONSE_CODES.OKAY elif get_int(self.dut.ahb_htrans) == AHB_LITE_TRANSFER_TYPE_ENCODING.NONSEQ: htrans = AHB_LITE_TRANSFER_TYPE_ENCODING.NONSEQ if get_int(self.dut.ahb_hwrite): if htrans != prev_htrans: self.rsp_driver_q.put_nowait(AHB_LITE_NOTIFICATION.AHB_LITE_WRITE) else: if htrans != prev_htrans: self.rsp_driver_q.put_nowait(AHB_LITE_NOTIFICATION.AHB_LITE_READ) try: ahb_hrdata, ahb_hready, ahb_hresp = self.req_driver_q.get_nowait() self.dut.ahb_hrdata.value = ahb_hrdata self.dut.ahb_hready.value = ahb_hready self.dut.ahb_hresp.value = ahb_hresp except QueueEmpty: self.dut.ahb_hrdata.value = 0 self.dut.ahb_hready.value = 0 self.dut.ahb_hresp.value = 0 async def req_monitor_q_bfm(self): while True: await RisingEdge(self.clk) if get_int(self.dut.ahb_hready): item = ( get_int(self.dut.ahb_hrdata), get_int(self.dut.ahb_hready), get_int(self.dut.ahb_hresp), ) await self.req_monitor_q.put(item) async def rsp_monitor_q_bfm(self): while True: await RisingEdge(self.clk) if get_int(self.dut.ahb_hready): sigs = get_signals(AHB_RSP_SIGNALS, self.dut) values = tuple(sig.value for sig in sigs) await self.rsp_monitor_q.put(values) def start_bfm(self): cocotb.start_soon(self.drive()) cocotb.start_soon(self.req_monitor_q_bfm()) cocotb.start_soon(self.rsp_monitor_q_bfm()) ================================================ FILE: verification/block/lib_axi4_to_ahb/ahb_lite_pkg.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 from enum import IntEnum AHB_DRV_SIGNALS = [ "ahb_hrdata", "ahb_hready", "ahb_hresp", ] AHB_RSP_SIGNALS = [ "ahb_haddr", "ahb_hburst", "ahb_hmastlock", "ahb_hprot", "ahb_hsize", "ahb_htrans", "ahb_hwrite", "ahb_hwdata", ] class AHB_LITE_RESPONSE_CODES(IntEnum): OKAY = 0 class AHB_LITE_TRANSFER_TYPE_ENCODING(IntEnum): IDLE = 0 BUSY = 1 NONSEQ = 2 SEQ = 3 class AHB_LITE_NOTIFICATION(IntEnum): AHB_LITE_WRITE = 1 AHB_LITE_READ = 2 AHB_LITE_IDLE = 3 ================================================ FILE: verification/block/lib_axi4_to_ahb/ahb_lite_seq.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random from ahb_lite_pkg import AHB_LITE_RESPONSE_CODES from pyuvm import uvm_sequence_item from common import BaseSeq class AHBLiteBaseSeqItem(uvm_sequence_item): def __init__(self, name): super().__init__(name) self.ahb_hrdata = 0 self.ahb_hready = 0 self.ahb_hresp = 0 def randomize(self): pass def __eq__(self, other): pass def __str__(self): return self.__class__.__name__ class AHBLiteInactiveSeqItem(AHBLiteBaseSeqItem): def __init__(self, name): super().__init__(name) class AHBLiteReadyReadSeqItem(AHBLiteBaseSeqItem): def __init__(self, name): super().__init__(name) self.ahb_hready = 1 self.ahb_hresp = AHB_LITE_RESPONSE_CODES.OKAY def randomize(self): self.ahb_hrdata = random.randint(0, 255) class AHBLiteReadyWriteSeqItem(AHBLiteBaseSeqItem): def __init__(self, name): super().__init__(name) self.ahb_hready = 1 self.ahb_hresp = AHB_LITE_RESPONSE_CODES.OKAY class AHBLiteReadyNoDataSeqItem(AHBLiteBaseSeqItem): def __init__(self, name): super().__init__(name) self.ahb_hready = 1 self.ahb_hresp = AHB_LITE_RESPONSE_CODES.OKAY class AHBLiteAcceptWriteSeq(BaseSeq): async def body(self): items = [ AHBLiteReadyNoDataSeqItem("AHBLiteReadyNoDataSeqItem"), AHBLiteReadyWriteSeqItem("AHBLiteReadyWriteSeqItem"), ] await self.run_items(items) class AHBLiteAcceptReadSeq(BaseSeq): async def body(self): items = [ AHBLiteReadyNoDataSeqItem("AHBLiteReadyNoDataSeqItem"), AHBLiteReadyReadSeqItem("AHBLiteReadyReadSeqItem"), ] await self.run_items(items) ================================================ FILE: verification/block/lib_axi4_to_ahb/axi_pkg.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 from enum import IntEnum AXI_W_CHAN_DRV_SIGNALS = [ "axi_awvalid", "axi_awid", "axi_awaddr", "axi_awsize", "axi_awprot", "axi_wvalid", "axi_wdata", "axi_wstrb", "axi_wlast", "axi_bready", ] AXI_W_CHAN_RSP_SIGNALS = [ "axi_awready", "axi_wready", "axi_bvalid", "axi_bresp", "axi_bid", ] AXI_W_CHAN_SIGNALS = AXI_W_CHAN_DRV_SIGNALS + AXI_W_CHAN_RSP_SIGNALS AXI_R_CHAN_DRV_SIGNALS = [ "axi_arvalid", "axi_arid", "axi_araddr", "axi_arsize", "axi_arprot", "axi_rready", ] AXI_R_CHAN_RSP_SIGNALS = [ "axi_arready", "axi_rvalid", "axi_rid", "axi_rdata", "axi_rresp", "axi_rlast", ] AXI_R_CHAN_SIGNALS = AXI_R_CHAN_DRV_SIGNALS + AXI_R_CHAN_RSP_SIGNALS class AXI_WRITE_RESPONSE_CODES(IntEnum): OKAY = 0 EXOKAY = 1 SLVERR = 2 DECERR = 3 DEFER = 4 TRANSFAULT = 5 RESERVED = 6 UNSUPPORTED = 7 class AXI_READ_RESPONSE_CODES(IntEnum): OKAY = 0 EXOKAY = 1 SLVERR = 2 DECERR = 3 PREFETCHED = 4 TRANSFAULT = 5 OKAYDIRTY = 6 RESERVED = 7 class AXI_AXSIZE_ENCODING(IntEnum): MAX_1B_TRANSFER = 0 MAX_2B_TRANSFER = 1 MAX_4B_TRANSFER = 2 MAX_8B_TRANSFER = 3 MAX_16B_TRANSFER = 4 MAX_32B_TRANSFER = 5 MAX_64B_TRANSFER = 6 MAX_128B_TRANSFER = 7 class AXI_NOTIFICATION(IntEnum): AXI_FREE = 1 AXI_BUSY = 2 AXI_AREAD_HANDSHAKE = 3 AXI_READ_HANDSHAKE = 4 ================================================ FILE: verification/block/lib_axi4_to_ahb/axi_r_agent.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import cocotb import pyuvm from axi_r_bfm import AXIReadChannelBFM from cocotb.queue import QueueEmpty from cocotb.triggers import RisingEdge from pyuvm import ConfigDB, uvm_agent, uvm_analysis_port, uvm_driver, uvm_sequencer from common import BaseMonitor class AXIReadChannelAgent(uvm_agent): def build_phase(self): self.seqr = uvm_sequencer("seqr", self) ConfigDB().set(None, "*", "axi_r_seqr", self.seqr) self.monitor = AXIReadChannelMonitor("axi_r_agent", self) self.driver = AXIReadChannelDriver("axi_r_driver", self) def connect_phase(self): self.driver.seq_item_port.connect(self.seqr.seq_item_export) class AXIReadChannelDriver(uvm_driver): def build_phase(self): self.ap = uvm_analysis_port("ap", self) self.rst_n = cocotb.top.rst_l self.clk = cocotb.top.clk def start_of_simulation_phase(self): self.bfm = AXIReadChannelBFM() async def run_phase(self): self.bfm.start_bfm() await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: await RisingEdge(self.rst_n) self.logger.info("Agent: AXI Read: Reset Posedge") try: pending = 1 axi_notification = self.bfm.rsp_driver_q.get_nowait() except QueueEmpty: pending = 0 if pending: self.seq_item_port.put_response(axi_notification) self.seq_item_port.put_response(3) try: item = await self.seq_item_port.get_next_item() await self.drive(item) self.logger.debug(f"Agent: AXI Read: Driven: {item}") self.seq_item_port.item_done() except QueueEmpty: pass async def drive(self, item): await self.bfm.req_driver_q_put( item.axi_arvalid, item.axi_arid, item.axi_araddr, item.axi_arsize, item.axi_arprot, item.axi_rready, ) class AXIReadChannelMonitor(BaseMonitor): def __init__(self, name, parent): super().__init__(name, parent) def build_phase(self): super().build_phase() self.bfm = AXIReadChannelBFM() ================================================ FILE: verification/block/lib_axi4_to_ahb/axi_r_bfm.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import cocotb from axi_pkg import AXI_NOTIFICATION, AXI_R_CHAN_RSP_SIGNALS from cocotb.queue import QueueEmpty from cocotb.triggers import RisingEdge from pyuvm import UVMQueue, utility_classes, uvm_root from common import get_int, get_signals class AXIReadChannelBFM(metaclass=utility_classes.Singleton): def __init__(self): self.dut = cocotb.top self.rst_n = cocotb.top.rst_l self.clk = cocotb.top.clk self.req_driver_q = UVMQueue(maxsize=1) self.rsp_driver_q = UVMQueue(maxsize=1) self.req_monitor_q = UVMQueue(maxsize=0) self.rsp_monitor_q = UVMQueue(maxsize=0) self.TIMEOUT_THRESHOLD = 20 async def req_driver_q_put( self, axi_arvalid, axi_arid, axi_araddr, axi_arsize, axi_arprot, axi_rready, ): item = ( axi_arvalid, axi_arid, axi_araddr, axi_arsize, axi_arprot, axi_rready, ) await self.req_driver_q.put(item) async def req_monitor_q_get(self): item = await self.req_monitor_q.get() return item async def rsp_monitor_q_get(self): result = await self.rsp_monitor_q.get() return result async def drive(self): await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: self.dut.axi_arvalid.value = 0 self.dut.axi_arid.value = 0 self.dut.axi_araddr.value = 0 self.dut.axi_arsize.value = 0 self.dut.axi_arprot.value = 0 self.dut.axi_rready.value = 0 await RisingEdge(self.rst_n) await RisingEdge(self.clk) try: ( axi_arvalid, axi_arid, axi_araddr, axi_arsize, axi_arprot, axi_rready, ) = self.req_driver_q.get_nowait() self.dut.axi_arvalid.value = axi_arvalid self.dut.axi_arid.value = axi_arid self.dut.axi_araddr.value = axi_araddr self.dut.axi_arsize.value = axi_arsize self.dut.axi_arprot.value = axi_arprot self.dut.axi_rready.value = axi_rready except QueueEmpty: pass # Handshake ARVALID <-> ARREADY if get_int(self.dut.axi_arvalid): timeout = 0 while get_int(self.dut.axi_arready) == 0: timeout += 1 self.rsp_driver_q.put_nowait(AXI_NOTIFICATION.AXI_BUSY) await RisingEdge(self.clk) if timeout > self.TIMEOUT_THRESHOLD: raise TimeoutError("Transaction Request Handshake Timeout: AXI Read") async def req_monitor_q_bfm(self): await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: await RisingEdge(self.rst_n) await RisingEdge(self.clk) if get_int(self.dut.axi_arvalid): if get_int(self.dut.axi_arready): item = ( get_int(self.dut.axi_arvalid), get_int(self.dut.axi_arid), get_int(self.dut.axi_araddr), get_int(self.dut.axi_arsize), get_int(self.dut.axi_arprot), get_int(self.dut.axi_rready), ) await self.req_monitor_q.put(item) async def rsp_monitor_q_bfm(self): await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: await RisingEdge(self.rst_n) await RisingEdge(self.clk) if get_int(self.dut.axi_rvalid): if get_int(self.dut.axi_rready): sigs = get_signals(AXI_R_CHAN_RSP_SIGNALS, self.dut) values = tuple(sig.value for sig in sigs) await self.rsp_monitor_q.put(values) def start_bfm(self): cocotb.start_soon(self.drive()) cocotb.start_soon(self.req_monitor_q_bfm()) cocotb.start_soon(self.rsp_monitor_q_bfm()) ================================================ FILE: verification/block/lib_axi4_to_ahb/axi_r_seq.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random from axi_pkg import AXI_AXSIZE_ENCODING from pyuvm import ConfigDB, uvm_sequence_item from common import BaseSeq class AXIReadBaseSeqItem(uvm_sequence_item): def __init__(self, name): super().__init__(name) self.AXI_DATA_WIDTH = ConfigDB().get(None, "", "AXI_DATA_WIDTH") self.AXI_NUM_STRB_BITS = int(self.AXI_DATA_WIDTH / 8) self.axi_arvalid = 0 self.axi_arid = 0 self.axi_araddr = 0 self.axi_arsize = int(AXI_AXSIZE_ENCODING.MAX_8B_TRANSFER) self.axi_arprot = 0 self.axi_rready = 0 def randomize(self): pass def __eq__(self, other): pass def __str__(self): return self.__class__.__name__ class AXIReadTransactionRequestSeqItem(AXIReadBaseSeqItem): def __init__(self, name): super().__init__(name) self.axi_arvalid = 1 def randomize(self): self.axi_araddr = 8 * random.randint(0, 0x1FFFFFFF) class AXIReadResponseReadSeqItem(AXIReadBaseSeqItem): def __init__( self, name, ): super().__init__(name) self.axi_rready = 1 class AXIReadInactiveSeqItem(AXIReadBaseSeqItem): def __init__(self, name): super().__init__(name) self.axi_arsize = 0 class AXIReadTransactionRequestSeq(BaseSeq): async def body(self): items = [ AXIReadTransactionRequestSeqItem("AXIReadTransactionRequestSeqItem"), AXIReadInactiveSeqItem("AXIReadInactiveSeqItem"), ] await self.run_items(items) class AXIReadTransactionResponseSeq(BaseSeq): async def body(self): items = [ AXIReadResponseReadSeqItem("AXIReadLastDataSeqItem"), AXIReadInactiveSeqItem("AXIReadInactiveSeqItem"), ] await self.run_items(items) ================================================ FILE: verification/block/lib_axi4_to_ahb/axi_w_agent.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import cocotb from axi_w_bfm import AXIWriteChannelBFM from axi_w_seq import ( AXIWriteInactiveSeqItem, AXIWriteLastDataSeqItem, AXIWriteResponseWriteSeqItem, AXIWriteTransactionRequestSeqItem, ) from cocotb.queue import QueueEmpty from cocotb.triggers import RisingEdge from pyuvm import ConfigDB, uvm_agent, uvm_driver, uvm_sequencer from common import BaseMonitor class AXIWriteChannelAgent(uvm_agent): """ Seqr <---> Driver Monitor <--^ """ def build_phase(self): self.seqr = uvm_sequencer("seqr", self) ConfigDB().set(None, "*", "axi_w_seqr", self.seqr) self.monitor = AXIWriteChannelMonitor("axi_w_agent", self) self.driver = AXIWriteChannelDriver("axi_w_driver", self) def connect_phase(self): self.driver.seq_item_port.connect(self.seqr.seq_item_export) class AXIWriteChannelDriver(uvm_driver): def build_phase(self): self.rst_n = cocotb.top.rst_l def start_of_simulation_phase(self): self.bfm = AXIWriteChannelBFM() async def run_phase(self): self.bfm.start_bfm() await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: await RisingEdge(self.rst_n) self.logger.info("Agent: AXI Write: Reset Posedge") try: item = await self.seq_item_port.get_next_item() except QueueEmpty: pass if isinstance(item, AXIWriteInactiveSeqItem): await self.drive(item) self.logger.debug(f"Driven: {item}") self.seq_item_port.item_done() if isinstance(item, AXIWriteTransactionRequestSeqItem): await self.drive(item) self.logger.debug(f"Driven: {item}") await self.wait_handshake(sig_name="axi_awready") self.seq_item_port.item_done() if isinstance(item, AXIWriteLastDataSeqItem): await self.drive(item) self.logger.debug(f"Driven: {item}") await self.wait_handshake(sig_name="axi_wready") self.seq_item_port.item_done() if isinstance(item, AXIWriteResponseWriteSeqItem): await self.drive(item) await self.wait_handshake(sig_name="axi_bvalid") self.logger.debug(f"Driven: {item}") self.seq_item_port.item_done() async def wait_handshake(self, sig_name=None, TIMEOUT_THRESHOLD=30): timeout = 0 while True: timeout += 1 await RisingEdge(self.bfm.clk) sig_handle = getattr(self.bfm.dut, sig_name) if sig_handle.value: break if timeout > TIMEOUT_THRESHOLD: raise TimeoutError(f"Transaction Request Handshake Timeout: AXI Write: {sig_name}") async def drive(self, item): await self.bfm.req_driver_q_put( item.axi_awvalid, item.axi_awid, item.axi_awaddr, item.axi_awsize, item.axi_awprot, item.axi_wvalid, item.axi_wdata, item.axi_wstrb, item.axi_wlast, item.axi_bready, ) class AXIWriteChannelMonitor(BaseMonitor): def __init__(self, name, parent): super().__init__(name, parent) def build_phase(self): super().build_phase() self.bfm = AXIWriteChannelBFM() ================================================ FILE: verification/block/lib_axi4_to_ahb/axi_w_bfm.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import cocotb from axi_pkg import AXI_W_CHAN_RSP_SIGNALS from cocotb.queue import QueueEmpty from cocotb.triggers import RisingEdge from pyuvm import UVMQueue, utility_classes, uvm_root from common import get_int, get_signals class AXIWriteChannelBFM(metaclass=utility_classes.Singleton): def __init__(self): self.dut = cocotb.top self.rst_n = cocotb.top.rst_l self.clk = cocotb.top.clk self.req_driver_q = UVMQueue(maxsize=1) self.req_monitor_q = UVMQueue() self.rsp_monitor_q = UVMQueue() async def req_driver_q_put( self, axi_awvalid, axi_awid, axi_awaddr, axi_awsize, axi_awprot, axi_wvalid, axi_wdata, axi_wstrb, axi_wlast, axi_bready, ): item = ( axi_awvalid, axi_awid, axi_awaddr, axi_awsize, axi_awprot, axi_wvalid, axi_wdata, axi_wstrb, axi_wlast, axi_bready, ) await self.req_driver_q.put(item) async def req_monitor_q_get(self): item = await self.req_monitor_q.get() return item async def rsp_monitor_q_get(self): result = await self.rsp_monitor_q.get() return result async def drive(self): await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: self.dut.axi_awvalid.value = 0 self.dut.axi_awid.value = 0 self.dut.axi_awaddr.value = 0 self.dut.axi_awsize.value = 0 self.dut.axi_awprot.value = 0 self.dut.axi_wvalid.value = 0 self.dut.axi_wdata.value = 0 self.dut.axi_wstrb.value = 0 self.dut.axi_wlast.value = 0 self.dut.axi_bready.value = 0 await RisingEdge(self.rst_n) await RisingEdge(self.clk) try: ( axi_awvalid, axi_awid, axi_awaddr, axi_awsize, axi_awprot, axi_wvalid, axi_wdata, axi_wstrb, axi_wlast, axi_bready, ) = self.req_driver_q.get_nowait() self.dut.axi_awvalid.value = axi_awvalid self.dut.axi_awid.value = axi_awid self.dut.axi_awaddr.value = axi_awaddr self.dut.axi_awsize.value = axi_awsize self.dut.axi_awprot.value = axi_awprot self.dut.axi_wvalid.value = axi_wvalid self.dut.axi_wdata.value = axi_wdata self.dut.axi_wstrb.value = axi_wstrb self.dut.axi_wlast.value = axi_wlast self.dut.axi_bready.value = axi_bready except QueueEmpty: pass async def req_monitor_q_bfm(self): await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: await RisingEdge(self.rst_n) await RisingEdge(self.clk) send_item = 0 if get_int(self.dut.axi_awvalid): if get_int(self.dut.axi_awready): send_item = 1 if get_int(self.dut.axi_wvalid): if get_int(self.dut.axi_wready): send_item = 1 if send_item: item = ( get_int(self.dut.axi_awvalid), get_int(self.dut.axi_awid), get_int(self.dut.axi_awaddr), get_int(self.dut.axi_awsize), get_int(self.dut.axi_awprot), get_int(self.dut.axi_wvalid), get_int(self.dut.axi_wdata), get_int(self.dut.axi_wstrb), get_int(self.dut.axi_wlast), get_int(self.dut.axi_bready), ) await self.req_monitor_q.put(item) async def rsp_monitor_q_bfm(self): await RisingEdge(self.rst_n) while True: if self.rst_n.value == 0: await RisingEdge(self.rst_n) await RisingEdge(self.clk) if get_int(self.dut.axi_bvalid): if get_int(self.dut.axi_bready): sigs = get_signals(AXI_W_CHAN_RSP_SIGNALS, self.dut) values = tuple(sig.value for sig in sigs) await self.rsp_monitor_q.put(values) def start_bfm(self): cocotb.start_soon(self.drive()) cocotb.start_soon(self.req_monitor_q_bfm()) cocotb.start_soon(self.rsp_monitor_q_bfm()) ================================================ FILE: verification/block/lib_axi4_to_ahb/axi_w_seq.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random from axi_pkg import AXI_AXSIZE_ENCODING from cocotb.types import LogicArray from pyuvm import ConfigDB, uvm_sequence_item from common import BaseSeq class AXIWriteBaseSeqItem(uvm_sequence_item): def __init__(self, name): super().__init__(name) self.AXI_DATA_WIDTH = ConfigDB().get(None, "", "AXI_DATA_WIDTH") self.AXI_NUM_STRB_BITS = int(self.AXI_DATA_WIDTH / 8) self.axi_awvalid = 0 self.axi_awid = 0 self.axi_awaddr = 0 self.axi_awsize = int(AXI_AXSIZE_ENCODING.MAX_8B_TRANSFER) self.axi_awprot = 0 self.axi_wvalid = 0 self.axi_wdata = 0 self.axi_wstrb = LogicArray("1" * self.AXI_NUM_STRB_BITS) self.axi_wlast = 0 self.axi_bready = 0 def randomize(self): pass def __eq__(self, other): pass def __str__(self): return self.__class__.__name__ class AXIWriteTransactionRequestSeqItem(AXIWriteBaseSeqItem): def __init__(self, name): super().__init__(name) self.axi_awvalid = 1 def randomize(self): self.axi_awid = random.randint(0, 1) self.axi_awaddr = 8 * random.randint(0, 0x1FFFFFFF) class AXIWriteDataSeqItem(AXIWriteBaseSeqItem): def __init__(self, name): super().__init__(name) self.axi_wvalid = 1 self.axi_wstrb = LogicArray("1" * self.AXI_NUM_STRB_BITS) def randomize(self): self.axi_wdata = random.randint(0, 0xFFFFFFFFFFFFFFFF) class AXIWriteLastDataSeqItem(AXIWriteDataSeqItem): def __init__(self, name): super().__init__(name) self.axi_wlast = 1 class AXIWriteResponseWriteSeqItem(AXIWriteBaseSeqItem): def __init__( self, name, ): super().__init__(name) self.axi_bready = 1 class AXIWriteInactiveSeqItem(AXIWriteBaseSeqItem): def __init__(self, name): super().__init__(name) self.axi_awsize = 0 self.axi_wstrb = 0 class AXIWriteTransactionRequestSeq(BaseSeq): async def body(self): items = [ AXIWriteInactiveSeqItem("AXIWriteInactiveSeqItem"), AXIWriteTransactionRequestSeqItem("AXIWriteTransactionRequestSeqItem"), AXIWriteInactiveSeqItem("AXIWriteInactiveSeqItem"), ] await self.run_items(items) class AXIWriteDataSeq(BaseSeq): async def body(self): items = [ AXIWriteInactiveSeqItem("AXIWriteInactiveSeqItem"), AXIWriteLastDataSeqItem("AXIWriteLastDataSeqItem"), AXIWriteInactiveSeqItem("AXIWriteInactiveSeqItem"), ] await self.run_items(items) class AXIWriteResponseSeq(BaseSeq): async def body(self): items = [ AXIWriteInactiveSeqItem("AXIWriteInactiveSeqItem"), AXIWriteResponseWriteSeqItem("AXIWriteLastDataSeqItem"), AXIWriteInactiveSeqItem("AXIWriteInactiveSeqItem"), ] await self.run_items(items) ================================================ FILE: verification/block/lib_axi4_to_ahb/cm.cfg ================================================ +tree * -node axi4_to_ahb.ahb_hprot[3:1] // Tied to 3'001 ================================================ FILE: verification/block/lib_axi4_to_ahb/common.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import logging import cocotb from pyuvm import uvm_analysis_port, uvm_component, uvm_sequence def collect_signals(signals, uut, obj): """ Collects signal objects from UUT and attaches them to the given object """ for sig in signals: if hasattr(uut, sig): s = getattr(uut, sig) else: s = None logging.error("Module {} does not have a signal '{}'".format(str(uut), sig)) setattr(obj, sig, s) def get_int(signal): try: sig = int(signal.value) except ValueError: sig = 0 return sig def get_signals(signals, obj): """ Returns signal objects attached to object. It is presumed that "signals" is a list of strings. """ attrs = [] for sig in signals: if hasattr(obj, sig): attrs.append(getattr(obj, sig)) else: raise Exception(f"Module {obj} does not have a signal {sig}") return attrs class BaseSeq(uvm_sequence): async def run_items(self, items): for item in items: await self.start_item(item) item.randomize() await self.finish_item(item) class BaseMonitor(uvm_component): def __init__(self, name, parent): super().__init__(name, parent) def build_phase(self): self.ap_req = uvm_analysis_port("ap_req", self) self.ap_rsp = uvm_analysis_port("ap_rsp", self) self.bfm = None async def monitor_req(self): while True: datum = await self.bfm.req_monitor_q_get() self.logger.debug(f"monitor_req: {datum}") self.ap_req.write(datum) async def monitor_rsp(self): while True: datum = await self.bfm.rsp_monitor_q_get() self.logger.debug(f"monitor_rsp: {datum}") self.ap_rsp.write(datum) async def run_phase(self): cocotb.start_soon(self.monitor_req()) cocotb.start_soon(self.monitor_rsp()) ================================================ FILE: verification/block/lib_axi4_to_ahb/coordinator_seq.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import cocotb from ahb_lite_pkg import AHB_LITE_NOTIFICATION from ahb_lite_seq import AHBLiteAcceptReadSeq, AHBLiteAcceptWriteSeq from axi_r_seq import AXIReadTransactionRequestSeq, AXIReadTransactionResponseSeq from axi_w_seq import ( AXIWriteDataSeq, AXIWriteResponseSeq, AXIWriteTransactionRequestSeq, ) from cocotb.triggers import RisingEdge from pyuvm import ConfigDB, uvm_root, uvm_sequence class CoordinatorSeq(uvm_sequence): async def axi_write(self, axi_seqr, ahb_seqr): axi_trq_seq = AXIWriteTransactionRequestSeq() axi_w_seq = AXIWriteDataSeq() axi_wresp_seq = AXIWriteResponseSeq() # Write Request await axi_trq_seq.start(axi_seqr) await self.delay(5) # Write Data await axi_w_seq.start(axi_seqr) # Handle AHB Response await self.ahb_response_handler(ahb_seqr=ahb_seqr, is_read=False) # Write Response await axi_wresp_seq.start(axi_seqr) async def axi_read(self, axi_seqr, ahb_seqr): axi_trq_seq = AXIReadTransactionRequestSeq() axi_rresp_seq = AXIReadTransactionResponseSeq() # Read Request await axi_trq_seq.start(axi_seqr) await self.delay(5) # Handle AHB Response await self.ahb_response_handler(ahb_seqr=ahb_seqr, is_read=True) await self.delay(5) # Read Response await axi_rresp_seq.start(axi_seqr) async def delay(self, i): for _ in range(i): await RisingEdge(cocotb.top.clk) async def ahb_response_handler(self, ahb_seqr, is_read=True): ahb_read_response_seq = AHBLiteAcceptReadSeq("ahb_accept_read") ahb_write_response_seq = AHBLiteAcceptWriteSeq("ahb_accept_write") response = await ahb_seqr.seq_item_export.get_response() expected_response = ( AHB_LITE_NOTIFICATION.AHB_LITE_READ if is_read else AHB_LITE_NOTIFICATION.AHB_LITE_WRITE ) if response == expected_response: info_string = "CoordinatorSeq: AHB READ" if is_read else "CoordinatorSeq: AHB WRITE" uvm_root().logger.info(info_string) if is_read: await ahb_read_response_seq.start(ahb_seqr) else: await ahb_write_response_seq.start(ahb_seqr) else: raise ValueError(f"Expected response: {expected_response}. Got: {response}.") class TestWriteChannelSeq(CoordinatorSeq): async def body(self): ahb_seqr = ConfigDB().get(None, "", "ahb_seqr") axi_seqr = ConfigDB().get(None, "", "axi_w_seqr") NUM_TRANSACTIONS_PER_TEST = ConfigDB().get(None, "", "NUM_TRANSACTIONS_PER_TEST") for _ in range(NUM_TRANSACTIONS_PER_TEST): await self.axi_write(axi_seqr=axi_seqr, ahb_seqr=ahb_seqr) await self.delay(10) class TestReadChannelSeq(CoordinatorSeq): async def body(self): ahb_seqr = ConfigDB().get(None, "", "ahb_seqr") axi_seqr = ConfigDB().get(None, "", "axi_r_seqr") NUM_TRANSACTIONS_PER_TEST = ConfigDB().get(None, "", "NUM_TRANSACTIONS_PER_TEST") for _ in range(NUM_TRANSACTIONS_PER_TEST): await self.axi_read(axi_seqr=axi_seqr, ahb_seqr=ahb_seqr) await self.delay(10) class TestBothChannelsSeq(CoordinatorSeq): async def body(self): ahb_seqr = ConfigDB().get(None, "", "ahb_seqr") axi_w_seqr = ConfigDB().get(None, "", "axi_w_seqr") axi_r_seqr = ConfigDB().get(None, "", "axi_r_seqr") NUM_TRANSACTIONS_PER_TEST = ConfigDB().get(None, "", "NUM_TRANSACTIONS_PER_TEST") test_all_q = [] for _ in range(NUM_TRANSACTIONS_PER_TEST): rw = random.randint(0, 1) test_all_q += ["READ"] if rw else ["WRITE"] uvm_root().logger.info(f"TestBothChannelsSeq: Test Sequence: {test_all_q}") for i in range(NUM_TRANSACTIONS_PER_TEST): if test_all_q[i] == "READ": await self.axi_read(axi_seqr=axi_r_seqr, ahb_seqr=ahb_seqr) elif test_all_q[i] == "WRITE": await self.axi_write(axi_seqr=axi_w_seqr, ahb_seqr=ahb_seqr) else: raise ValueError("Unexpected value in sequence. Should be READ or WRITE.") ================================================ FILE: verification/block/lib_axi4_to_ahb/test_axi.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from cocotb.queue import QueueFull from coordinator_seq import TestBothChannelsSeq from testbench import BaseTest @pyuvm.test() class TestAXI(BaseTest): def end_of_elaboration_phase(self): self.seq = TestBothChannelsSeq.create("stimulus") async def run(self): self.raise_objection() await self.seq.start() self.drop_objection() ================================================ FILE: verification/block/lib_axi4_to_ahb/test_axi_read_channel.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from cocotb.queue import QueueFull from coordinator_seq import TestReadChannelSeq from testbench import BaseTest @pyuvm.test() class TestAXIReadChannel(BaseTest): def end_of_elaboration_phase(self): self.seq = TestReadChannelSeq.create("stimulus") async def run(self): self.raise_objection() await self.seq.start() self.drop_objection() ================================================ FILE: verification/block/lib_axi4_to_ahb/test_axi_write_channel.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import pyuvm from coordinator_seq import TestWriteChannelSeq from testbench import BaseTest @pyuvm.test() class TestAXIWriteChannel(BaseTest): def end_of_elaboration_phase(self): self.seq = TestWriteChannelSeq.create("stimulus") async def run(self): self.raise_objection() await self.seq.start() self.drop_objection() ================================================ FILE: verification/block/lib_axi4_to_ahb/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import logging import os from decimal import Decimal import cocotb from ahb_lite_agent import AHBLiteAgent from ahb_lite_pkg import AHB_LITE_RESPONSE_CODES, AHB_LITE_TRANSFER_TYPE_ENCODING from axi_pkg import AXI_READ_RESPONSE_CODES, AXI_WRITE_RESPONSE_CODES from axi_r_agent import AXIReadChannelAgent from axi_w_agent import AXIWriteChannelAgent from cocotb.clock import Clock from cocotb.triggers import ClockCycles, Timer from pyuvm import ( ConfigDB, uvm_component, uvm_env, uvm_get_port, uvm_report_object, uvm_test, uvm_tlm_analysis_fifo, ) class Scoreboard(uvm_component): def build_phase(self): self.axi_w_req_fifo = uvm_tlm_analysis_fifo("axi_w_req_fifo", self) self.axi_w_rsp_fifo = uvm_tlm_analysis_fifo("axi_w_rsp_fifo", self) self.axi_w_req_get_port = uvm_get_port("axi_w_req_get_port", self) self.axi_w_rsp_get_port = uvm_get_port("axi_w_rsp_get_port", self) self.axi_w_req_export = self.axi_w_req_fifo.analysis_export self.axi_w_rsp_export = self.axi_w_rsp_fifo.analysis_export self.axi_r_req_fifo = uvm_tlm_analysis_fifo("axi_r_req_fifo", self) self.axi_r_rsp_fifo = uvm_tlm_analysis_fifo("axi_r_rsp_fifo", self) self.axi_r_req_get_port = uvm_get_port("axi_r_req_get_port", self) self.axi_r_rsp_get_port = uvm_get_port("axi_r_rsp_get_port", self) self.axi_r_req_export = self.axi_r_req_fifo.analysis_export self.axi_r_rsp_export = self.axi_r_rsp_fifo.analysis_export self.ahb_req_fifo = uvm_tlm_analysis_fifo("ahb_req_fifo", self) self.ahb_rsp_fifo = uvm_tlm_analysis_fifo("ahb_rsp_fifo", self) self.ahb_req_get_port = uvm_get_port("ahb_req_get_port", self) self.ahb_rsp_get_port = uvm_get_port("ahb_rsp_get_port", self) self.ahb_req_export = self.ahb_req_fifo.analysis_export self.ahb_rsp_export = self.ahb_rsp_fifo.analysis_export def connect_phase(self): self.axi_w_req_get_port.connect(self.axi_w_req_fifo.get_export) self.axi_w_rsp_get_port.connect(self.axi_w_rsp_fifo.get_export) self.axi_r_req_get_port.connect(self.axi_r_req_fifo.get_export) self.axi_r_rsp_get_port.connect(self.axi_r_rsp_fifo.get_export) self.ahb_req_get_port.connect(self.ahb_req_fifo.get_export) self.ahb_rsp_get_port.connect(self.ahb_rsp_fifo.get_export) def check_phase(self): passed = True self.logger.info("Check Phase") axi_w_transactions = self.check_axi_write() axi_r_transactions = self.check_axi_read() ahb_transactions = self.check_ahb() ahb_w_transactions = [] ahb_r_transactions = [] for transaction in ahb_transactions: if transaction["TYPE"] == "WRITE": ahb_w_transactions.append(transaction) else: ahb_r_transactions.append(transaction) assert len(axi_w_transactions) == len(ahb_w_transactions) assert len(axi_r_transactions) == len(ahb_r_transactions) num_w_transactions = len(axi_w_transactions) for id in range(num_w_transactions): self.logger.info(f"AXI Wrote {axi_w_transactions[id]}") self.logger.info(f"AHB Wrote {ahb_w_transactions[id]}") assert axi_w_transactions[id] == ahb_w_transactions[id] num_r_transactions = len(axi_r_transactions) for id in range(num_r_transactions): self.logger.info(f"AXI Read {axi_r_transactions[id]}") self.logger.info(f"AHB Read {ahb_r_transactions[id]}") assert axi_r_transactions[id] == ahb_r_transactions[id] assert passed def check_axi_write(self): axi_w_req_list = [] while self.axi_w_req_get_port.can_get(): _, item = self.axi_w_req_get_port.try_get() axi_w_req_dict = {} awvalid = item[0] awaddr = item[2] wvalid = item[5] wdata = item[6] if awvalid: axi_w_req_dict["ADDRESS"] = awaddr elif wvalid: axi_w_req_dict["DATA"] = wdata else: raise ValueError("Unexpected item in monitor queue.") axi_w_req_list.append(axi_w_req_dict) # For each request there should be one data item transaction_requests = axi_w_req_list[0::2] transaction_data = axi_w_req_list[1::2] assert len(transaction_requests) == len(transaction_data) num_transactions = len(transaction_data) axi_w_transactions = [] for id in range(num_transactions): axi_w_transaction = {} axi_w_transaction["TYPE"] = "WRITE" axi_w_transaction["ADDRESS"] = transaction_requests[id]["ADDRESS"] axi_w_transaction["DATA"] = transaction_data[id]["DATA"] axi_w_transactions.append(axi_w_transaction) # Check if each transaction is confirmed axi_w_rsp_list = [] while self.axi_w_rsp_get_port.can_get(): _, item = self.axi_w_rsp_get_port.try_get() axi_w_rsp_dict = {} bvalid = item[2] bresp = item[3] assert bvalid == 1 assert bresp == AXI_WRITE_RESPONSE_CODES.OKAY axi_w_rsp_dict["STATUS"] = "OKAY" axi_w_rsp_list.append(axi_w_rsp_dict) assert len(transaction_requests) == len(axi_w_rsp_list) self.logger.debug(f"AXI WRITE TRANSACTIONS {axi_w_transactions}") return axi_w_transactions def check_axi_read(self): axi_r_req_list = [] while self.axi_r_req_get_port.can_get(): _, item = self.axi_r_req_get_port.try_get() axi_r_req_dict = {} arvalid = item[0] araddr = item[2] assert arvalid == 1 axi_r_req_dict["TYPE"] = "READ" axi_r_req_dict["ADDRESS"] = araddr axi_r_req_list.append(axi_r_req_dict) self.logger.debug(f"AXI READ REQUESTS: {axi_r_req_list}") axi_r_rsp_list = [] while self.axi_r_rsp_get_port.can_get(): _, item = self.axi_r_rsp_get_port.try_get() axi_r_rsp_dict = {} rvalid = item[1] rdata = item[3] rresp = item[4] assert rvalid == 1 assert rresp == AXI_READ_RESPONSE_CODES.OKAY axi_r_rsp_dict["TYPE"] = "READ RESPONSE" axi_r_rsp_dict["DATA"] = int(rdata) axi_r_rsp_list.append(axi_r_rsp_dict) assert len(axi_r_req_list) == len(axi_r_rsp_list) axi_r_transactions = [] num_transactions = len(axi_r_req_list) for id in range(num_transactions): axi_r_transaction = {} axi_r_transaction["TYPE"] = "READ" axi_r_transaction["ADDRESS"] = axi_r_req_list[id]["ADDRESS"] axi_r_transaction["DATA"] = axi_r_rsp_list[id]["DATA"] axi_r_transactions.append(axi_r_transaction) self.logger.debug(f"AXI READ TRANSACTIONS {axi_r_transactions}") return axi_r_transactions def check_ahb(self): ahb_rsp_list = [] is_even = True ahb_rsp_dict = {} while self.ahb_rsp_get_port.can_get(): _, item = self.ahb_rsp_get_port.try_get() haddr = item[0] htrans = item[5] hwrite = item[6] hwdata = item[7] if is_even: assert htrans == AHB_LITE_TRANSFER_TYPE_ENCODING.NONSEQ if hwrite: ahb_rsp_dict["TYPE"] = "WRITE" ahb_rsp_dict["DATA"] = int(hwdata) else: ahb_rsp_dict["TYPE"] = "READ" ahb_rsp_dict["ADDRESS"] = int(haddr) if not is_even: ahb_rsp_list.append(ahb_rsp_dict) ahb_rsp_dict = {} is_even = not is_even self.logger.debug(f"ahb_rsp_list {ahb_rsp_list}") ahb_req_list = [] is_even = True ahb_req_dict = {} while self.ahb_req_get_port.can_get(): _, item = self.ahb_req_get_port.try_get() hrdata = item[0] hready = item[1] hresp = item[2] assert hready == 1 assert hresp == AHB_LITE_RESPONSE_CODES.OKAY if not is_even: ahb_req_dict["DATA"] = int(hrdata) ahb_req_list.append(ahb_req_dict) ahb_req_dict = {} is_even = not is_even self.logger.debug(f"ahb_req_list {ahb_req_list}") assert len(ahb_rsp_list) == len(ahb_req_list) ahb_transactions = [] num_transactions = len(ahb_rsp_list) for id in range(num_transactions): ahb_transaction = {} if ahb_rsp_list[id]["TYPE"] == "WRITE": ahb_transaction = ahb_rsp_list[id] ahb_transactions.append(ahb_transaction) continue else: ahb_transaction["TYPE"] = "READ" ahb_transaction["ADDRESS"] = ahb_rsp_list[id]["ADDRESS"] ahb_transaction["DATA"] = ahb_req_list[id]["DATA"] ahb_transactions.append(ahb_transaction) self.logger.debug(f"AHB Transactions {ahb_transactions}") return ahb_transactions class BaseEnvironment(uvm_env): def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "AXI_DATA_WIDTH", 64) ConfigDB().set(None, "*", "DUT_PRTY", cocotb.top.PRTY.value) ConfigDB().set(None, "*", "DUT_TAG", cocotb.top.TAG.value) ConfigDB().set(None, "*", "DUT_ID", cocotb.top.ID.value) ConfigDB().set(None, "*", "NUM_TRANSACTIONS_PER_TEST", 32) self.agent_axi_w = AXIWriteChannelAgent("axi_w_agent", self) self.agent_axi_r = AXIReadChannelAgent("axi_r_agent", self) self.agent_ahb = AHBLiteAgent("ahb_lite_agent", self) self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): self.agent_axi_w.monitor.ap_req.connect(self.scoreboard.axi_w_req_export) self.agent_axi_w.monitor.ap_rsp.connect(self.scoreboard.axi_w_rsp_export) self.agent_axi_r.monitor.ap_req.connect(self.scoreboard.axi_r_req_export) self.agent_axi_r.monitor.ap_rsp.connect(self.scoreboard.axi_r_rsp_export) self.agent_ahb.monitor.ap_req.connect(self.scoreboard.ahb_req_export) self.agent_ahb.monitor.ap_rsp.connect(self.scoreboard.ahb_rsp_export) class BaseTest(uvm_test): """ """ def __init__(self, name, parent): super().__init__(name, parent) # Synchronize pyuvm logging level with cocotb logging level. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = BaseEnvironment("env", self) cocotb.top.rst_l.value = 0 def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self, signalName, timeLength="100e-9", isActiveHigh=True): cocotb.top.rst_l.value = 0 cocotb.top.free_clk.value = 0 cocotb.top.bus_clk_en.value = 1 cocotb.top.clk_override.value = 0 cocotb.top.dec_tlu_force_halt.value = 0 cocotb.top.axi_awvalid.value = 0 cocotb.top.axi_awid.value = 0 cocotb.top.axi_awaddr.value = 0 cocotb.top.axi_awsize.value = 0 cocotb.top.axi_awprot.value = 0 cocotb.top.axi_wvalid.value = 0 cocotb.top.axi_wdata.value = 0 cocotb.top.axi_wstrb.value = 0 cocotb.top.axi_wlast.value = 0 cocotb.top.axi_bready.value = 0 cocotb.top.axi_arvalid.value = 0 cocotb.top.axi_arid.value = 0 cocotb.top.axi_araddr.value = 0 cocotb.top.axi_arsize.value = 0 cocotb.top.axi_arprot.value = 0 cocotb.top.axi_rready.value = 0 cocotb.top.ahb_hrdata.value = 0 cocotb.top.ahb_hready.value = 0 cocotb.top.ahb_hresp.value = 0 signal = getattr(cocotb.top, signalName) signal.value = int(isActiveHigh) self.config() await Timer(Decimal(timeLength), units="sec") signal.value = not int(isActiveHigh) def config(self): cocotb.top.scan_mode.value = 0 cocotb.top.bus_clk_en.value = 1 cocotb.top.clk_override.value = 0 cocotb.top.dec_tlu_force_halt.value = 0 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") self.start_clock("free_clk") clk = getattr(cocotb.top, "clk") # Issue reset resetLength = "10e-9" await self.do_reset(signalName="rst_l", timeLength=resetLength, isActiveHigh=False) await ClockCycles(clk, 2) await self.run() await ClockCycles(clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/lib_axi4_to_ahb/ucli.key ================================================ ================================================ FILE: verification/block/lsu_tl/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_lsu_trigger_wrapper VERILOG_SOURCES = \ $(TEST_DIR)/el2_lsu_trigger_wrapper.sv \ $(SRCDIR)/lsu/el2_lsu_trigger.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/lsu_tl/config.vlt ================================================ `verilator_config lint_off -rule WIDTHTRUNC -file "*/el2_lsu_trigger_wrapper.sv" lint_off -rule UNUSEDPARAM -file "*/el2_lsu_trigger_wrapper.sv" ================================================ FILE: verification/block/lsu_tl/el2_lsu_trigger_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_lsu_trigger_wrapper import el2_pkg::*; #( `include "el2_param.vh" ) ( // Unpacked [3:0] trigger_pkt_t input logic [3:0] select, input logic [3:0] match, input logic [3:0] store, input logic [3:0] load, input logic [3:0] execute, input logic [3:0] m, input logic [31:0] tdata[4], // Fields from lsu_pkt_m relevant in this test // input logic lsu_word, // input logic lsu_half, // input logic lsu_dma, // input logic lsu_valid, // input logic lsu_store, input logic [31:0] lsu_addr_m, // address input logic [31:0] store_data_m, // store data output logic [3:0] lsu_trigger_match_m // match result ); // Pack triggers el2_trigger_pkt_t [3:0] trigger_pkt_any; for (genvar i = 0; i < 4; i++) begin : g_trigger_assigns assign trigger_pkt_any[i].select = select[i]; assign trigger_pkt_any[i].match = match[i]; assign trigger_pkt_any[i].store = store[i]; assign trigger_pkt_any[i].load = load[i]; assign trigger_pkt_any[i].execute = execute[i]; assign trigger_pkt_any[i].m = m[i]; assign trigger_pkt_any[i].tdata2 = tdata[i]; end // Pack lsu_pkt_m el2_lsu_pkt_t lsu_pkt_m; assign lsu_pkt_m.word = 1; // lsu_word; assign lsu_pkt_m.half = 1; // lsu_half; assign lsu_pkt_m.dma = 0; // lsu_dma; assign lsu_pkt_m.valid = 1; // lsu_valid; assign lsu_pkt_m.store = 1; // lsu_store; // The trigger unit el2_lsu_trigger tu ( .* ); endmodule ================================================ FILE: verification/block/lsu_tl/test_lsu_tl.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseTest, TlSequence # ============================================================================= @pyuvm.test() class TestTriggerLogic(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TlSequence("stimulus") async def run_phase(self): self.raise_objection() # Run the actual test await self.run() self.drop_objection() async def run(self): await self.seq.start(self.env.tl_seqr) ================================================ FILE: verification/block/lsu_tl/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import copy import math import os import random import struct import pyuvm from cocotb.binary import BinaryValue from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from cocotb.types import Array, Range from pyuvm import * # ============================================================================== class TlInputItem(uvm_sequence_item): """ Trigger Logic output data """ def __init__(self, data=0, tdata=None, match=0): super().__init__("TlOutputItem") self.match = match self.data = data self.tdata = [None] * 4 if tdata is not None: for i in range(4): self.tdata[i] = tdata[i] def randomize(self): data = "" for i in range(31): # Sic. Last bit of PC is always 0 data += random.choice(["0", "1"]) data += "0" self.data = int(data, 2) self.match = 0 for i in range(4): matching = random.choice([False, True]) trigger = self.random_trigger(data, matching) self.match |= trigger["match"] << i self.tdata[i] = trigger["tdata"] def random_trigger(self, data, matching): """ Creates a trigger packet for data vector. It can be precised if the packet will be matching or not. """ # Select determines if we match against the PC or opcode, # TL in TLU does the first thing match = "" tdata = "" # Generate the matched part length = 0 if matching: length = random.randrange(32 + 1) if length > 0: tdata += data[:length] else: length = random.randrange(1, 32) for i in range(length): tdata += random.choice(["0", "1"]) # Assure a mismatch i = random.randrange(length) b = "1" if data[i] == "0" else "0" tdata = tdata[:i] + b + tdata[i + 1 :] # Generate the mask length = 32 - length if length == 0: match = "0" # Do full match else: match = "1" tdata += "0" + "1" * (length - 1) return {"match": int(match, 2), "tdata": int(tdata, 2)} class TlOutputItem(uvm_sequence_item): """ Trigger Logic output data """ def __init__(self, matches): super().__init__("TlOutputItem") self.matches = matches # ============================================================================== class TlDriver(uvm_driver): """ Trigger Logic driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: it = await self.seq_item_port.get_next_item() if isinstance(it, TlInputItem): self.dut.lsu_addr_m.value = it.data self.dut.store_data_m.value = it.data for i in range(4): self.dut.tdata[i].value = it.tdata[i] self.dut.match.value = it.match self.dut.select.value = 0b0000 self.dut.store.value = 0b1111 self.dut.load.value = 0b1111 self.dut.execute.value = 0b1111 self.dut.m.value = 0b1111 # Wait for monitors to read the values await Timer(period, "ns") else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class TlInputMonitor(uvm_component): """ Monitor for Trigger Logic inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: # Wait for the driver to set the input signals await Timer(period, "ns") data = int(self.dut.store_data_m.value) tdata = [None] * 4 for i in range(4): tdata[i] = int(self.dut.tdata[i].value) match = int(self.dut.match.value) self.ap.write(TlInputItem(data, tdata, match)) class TlOutputMonitor(uvm_component): """ Monitor for Trigger Logic outputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") while True: # Wait for the driver to set the input signals await Timer(period, "ns") matches = int(self.dut.lsu_trigger_match_m.value) self.ap.write(TlOutputItem(matches)) # ============================================================================== class TlScoreboard(uvm_component): """ Trigger Logic scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True # Change outputs to str and reproduce what TL does res = 0 match = item_inp.match data = f"{item_inp.data:032b}" for i in range(4): tdata = f"{item_inp.tdata[i]:032b}" if match & (1 << i): length = tdata.rindex("0") res |= (tdata[:length] == data[:length]) << i else: res |= (tdata == data) << i if item_out.matches != res: self.logger.error(f"Expected {res:04b} got {item_out.matches:04b}") for i in range(4): print(f"{item_inp.data:032b} (match {item_inp.tdata[i]:032b}") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class TlSequence(uvm_sequence): """ Base sequence of randomized 32-bit A and B operands along with operators picked randomly from the allowed set """ def __init__(self, name, ops=None): super().__init__(name) async def body(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") for i in range(count): item = TlInputItem() item.randomize() await self.start_item(item) await self.finish_item(item) # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 5000) # Sequencers self.tl_seqr = uvm_sequencer("tl_seqr", self) # Driver self.tl_drv = TlDriver("tl_drv", self, dut=cocotb.top) # Monitors self.inp_mon = TlInputMonitor("inp_mon", self, dut=cocotb.top) self.out_mon = TlOutputMonitor("out_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = TlScoreboard("scoreboard", self) def connect_phase(self): self.tl_drv.seq_item_port.connect(self.tl_seqr.seq_item_export) self.inp_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.out_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/noxfile.py ================================================ # Copyright (C) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import logging import os from xml.etree import ElementTree as ET import nox # nox quirk: in status.json, return code for failure is 0 # https://github.com/wntrblm/nox/blob/main/nox/sessions.py#L128C11-L128C11 nox.options.report = "status.json" nox.options.reuse_existing_virtualenvs = True # Test configuration blockPath = "." pipRequirementsPath = "requirements.txt" # Coverage types to collect coverageTypes = [ "all", ] # Used lint tools lintTools = [ "isort", # config in pyproject.toml "black", # config in pyproject.toml "flake8", # config in .flake8 ] def isSimFailure( resultsFile="results.xml", testsuites_name="results", verbose=False, suppress_rc=False ): """ Extract failure code from cocotb results.xml file Based on https://github.com/cocotb/cocotb/blob/master/bin/combine_results.py """ rc = 0 # Logging logger = logging.getLogger() logger.setLevel(logging.DEBUG) logHandler = logging.FileHandler(filename="parseResultsXML.log", mode="w", encoding="utf-8") logFormatter = logging.Formatter() logHandler.setFormatter(logFormatter) logger.addHandler(logHandler) logHandler.setLevel(logging.INFO) if verbose: logHandler.setLevel(logging.DEBUG) # Main result = ET.Element("testsuites", name=testsuites_name) logging.debug(f"Reading file {resultsFile}") tree = ET.parse(resultsFile) for ts in tree.iter("testsuite"): ts_name = ts.get("name") ts_package = ts.get("package") logging.debug(f"Testsuite name : {ts_name}, package : {ts_package}") use_element = None for existing in result: if existing.get("name") == ts.get("name") and existing.get("package") == ts.get( "package" ): use_element = existing break if use_element is None: result.append(ts) else: use_element.extend(list(ts)) if verbose: ET.dump(result) for testsuite in result.iter("testsuite"): for testcase in testsuite.iter("testcase"): for failure in testcase.iter("failure"): rc = 1 logging.info( "Failure in testsuite: '{}' classname: '{}' testcase: '{}' with parameters '{}'".format( testsuite.get("name"), testcase.get("classname"), testcase.get("name"), testsuite.get("package"), ) ) if suppress_rc: rc = 0 logging.shutdown() return rc def verify_block(session, blockName, testName, coverage=""): session.install("-r", pipRequirementsPath) testPath = os.path.join(blockPath, blockName) testNameXML = os.path.join(testName + ".xml") testNameXMLPath = os.path.join(testPath, testNameXML) testNameLog = os.path.join(testName + ".log") testNameLogPath = os.path.join(testPath, testNameLog) with open(testNameLogPath, "w") as testLog: session.run( "make", "-C", testPath, "all", "COVERAGE_TYPE=" + coverage, "MODULE=" + testName, "COCOTB_RESULTS_FILE=" + testNameXML, external=True, stdout=testLog, stderr=testLog, ) # Prevent coverage.dat and test log from being overwritten if coverage != "": coveragePath = testPath coverageName = "coverage.dat" coverageNamePath = os.path.join(coveragePath, coverageName) newCoverageName = "coverage_" + testName + "_" + coverage + ".dat" newCoverageNamePath = os.path.join(coveragePath, newCoverageName) os.rename(coverageNamePath, newCoverageNamePath) newTestNameLog = testName + "_" + coverage + ".log" newTestNameLogPath = os.path.join(testPath, newTestNameLog) os.rename(testNameLogPath, newTestNameLogPath) # Add check from results.xml to notify nox that test failed isTBFailure = isSimFailure(resultsFile=testNameXMLPath) if isTBFailure: raise Exception("SimFailure: cocotb failed. See test logs for more information.") @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["pic"]) @nox.parametrize( "testName", [ "test_reset", "test_clken", "test_config", "test_pending", "test_prioritization", "test_servicing", ], ) @nox.parametrize("coverage", coverageTypes) def pic_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["pic_gw"]) @nox.parametrize("testName", ["test_gateway"]) @nox.parametrize("coverage", coverageTypes) def pic_gw_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dec_tl"]) @nox.parametrize("testName", ["test_dec_tl"]) @nox.parametrize("coverage", coverageTypes) def dec_tl_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dec_ib"]) @nox.parametrize("testName", ["test_dec_ib"]) @nox.parametrize("coverage", coverageTypes) def dec_ib_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dma"]) @nox.parametrize( "testName", [ "test_reset", "test_read", "test_write", "test_address", "test_ecc", "test_debug_read", "test_debug_write", "test_debug_address", ], ) @nox.parametrize("coverage", coverageTypes) def dma_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["ifu_compress"]) @nox.parametrize("testName", ["test_compress"]) @nox.parametrize("coverage", coverageTypes) def ifu_compress_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["ifu_mem_ctl"]) @nox.parametrize("testName", ["test_miss", "test_err", "test_err_stop"]) @nox.parametrize("coverage", coverageTypes) def ifu_mem_ctl_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["exu_alu"]) @nox.parametrize( "testName", [ "test_arith", "test_logic", "test_zbb", "test_zbs", "test_zbp", "test_zba", ], ) @nox.parametrize("coverage", coverageTypes) def exu_alu_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["exu_mul"]) @nox.parametrize( "testName", [ "test_mul", ], ) @nox.parametrize("coverage", coverageTypes) def exu_mul_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["exu_div"]) @nox.parametrize( "testName", [ "test_div", ], ) @nox.parametrize("coverage", coverageTypes) def exu_div_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["iccm"]) @nox.parametrize( "testName", [ "test_readwrite", ], ) @nox.parametrize("coverage", coverageTypes) def iccm_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dccm"]) @nox.parametrize( "testName", [ "test_readwrite", ], ) @nox.parametrize("coverage", coverageTypes) def dccm_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dcls"]) @nox.parametrize( "testName", [ "test_lockstep", ], ) @nox.parametrize("coverage", coverageTypes) def dcls_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["lib_axi4_to_ahb"]) @nox.parametrize( "testName", [ "test_axi", "test_axi_read_channel", "test_axi_write_channel", ], ) @nox.parametrize("coverage", coverageTypes) def lib_axi4_to_ahb_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["lib_ahb_to_axi4"]) @nox.parametrize( "testName", [ "test_write", "test_read", ], ) @nox.parametrize("coverage", coverageTypes) def lib_ahb_to_axi4_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["pmp"]) @nox.parametrize( "testName", [ "test_xwr_access", "test_address_matching", "test_multiple_configs", ], ) @nox.parametrize("coverage", coverageTypes) def pmp_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["pmp_random"]) @nox.parametrize( "testName", [ "test_pmp_random", ], ) @nox.parametrize("coverage", coverageTypes) def pmp_random_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dec"]) @nox.parametrize( "testName", [ "test_dec", ], ) @nox.parametrize("coverage", coverageTypes) def dec_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dec_tlu_ctl"]) @nox.parametrize( "testName", [ "test_dec_tl", ], ) @nox.parametrize("coverage", coverageTypes) def dec_tlu_ctl_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dmi"]) @nox.parametrize( "testName", [ "test_jtag_ir", "test_dmi_read_write", "test_dmi_tap_fsm", ], ) @nox.parametrize("coverage", coverageTypes) def dmi_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["lsu_tl"]) @nox.parametrize("testName", ["test_lsu_tl"]) @nox.parametrize("coverage", coverageTypes) def lsu_tl_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(tags=["tests"]) @nox.parametrize("blockName", ["dec_pmp_ctl"]) @nox.parametrize("testName", ["test_dec_pmp_ctl"]) @nox.parametrize("coverage", coverageTypes) def dec_pmp_ctl_verify(session, blockName, testName, coverage): verify_block(session, blockName, testName, coverage) @nox.session(reuse_venv=True) def lint(session: nox.Session) -> None: """Options are defined in pyproject.toml and .flake8 files""" session.install(*lintTools) session.run("isort", ".") session.run("black", ".") session.run("flake8", ".") @nox.session() def test_lint(session: nox.Session) -> None: session.install(*lintTools) session.run("isort", "--check", ".") session.run("black", "--check", ".") session.run("flake8", ".") ================================================ FILE: verification/block/pic/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_pic_ctrl VERILOG_SOURCES = \ $(SRCDIR)/el2_pic_ctrl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/pic/test_clken.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 from copy import deepcopy import cocotb import pyuvm from cocotb.result import SimTimeoutError from cocotb.triggers import Edge, Lock, RisingEdge, Timer, with_timeout from pyuvm import * from testbench import BaseEnv, BaseTest, collect_signals # ============================================================================= class ClockEnableItem(uvm_sequence_item): def __init__(self, clk_en, io_clk_en): super().__init__("ClockEnableItem") self.clk_en = clk_en self.io_clk_en = io_clk_en class ClockStateItem(uvm_sequence_item): def __init__(self, state): super().__init__("ClockStateItem") self.state = deepcopy(state) # ============================================================================= class ClkenDriver(uvm_driver): """ A driver for clock gating override signals """ SIGNALS = [ "clk_override", "io_clk_override", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, ClockEnableItem): self.clk_override.value = it.clk_en self.io_clk_override.value = it.io_clk_en else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class ClkenMonitor(uvm_component): """ A monitor for clock gating override signals """ SIGNALS = [ "clk", "clk_override", "io_clk_override", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) self.prev_clk_override = 0 self.prev_io_clk_override = 0 def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Sample control signals await RisingEdge(self.clk) clk_override = int(self.clk_override.value) io_clk_override = int(self.io_clk_override.value) if ( self.prev_clk_override != clk_override or self.prev_io_clk_override != io_clk_override ): self.ap.write(ClockEnableItem(clk_override, io_clk_override)) self.prev_clk_override = clk_override self.prev_io_clk_override = io_clk_override # ============================================================================= class ClockMonitor(uvm_component): """ A monitor for clock signal activity. The monitor spawns one task per clock signal. Each task waits either for a signal transition or a fixed time equal to twice the expected clock period (its actually important that the time is greater than half-period) If, during the waiting time, the task detects any signal transition (1->0, 0->1), then it marks the signal as an active clock. Otherwise, the signal is marked as inactive. The main task of the monitor periodically samples the state vector reported by monitoring tasks and sends a message through its analysis port. This is scheduled to happen periodically every 5 * the expected clock period. The scheduling is chosen arbitrarily. """ SIGNALS = [ "pic_raddr_c1_clk", "pic_data_c1_clk", "pic_pri_c1_clk", "pic_int_c1_clk", "gw_config_c1_clk", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) self.lock = Lock() self.state = {sig: False for sig in self.SIGNALS} def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") # Start monitoring tasks for name in self.SIGNALS: cocotb.start_soon(self.monitor_clock(name)) # Periodically sample clock state and send messages while True: # Wait await Timer(period * 5, "ns") # Sample state and send item async with self.lock: self.ap.write(ClockStateItem(self.state)) async def monitor_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") signal = getattr(self, name) # Monitor the clock signal while True: # Wait for clock edges with timeout try: await with_timeout(Edge(signal), 2.0 * period, "ns") toggling = True except SimTimeoutError: toggling = False # Update the state async with self.lock: self.state[name] = toggling # ============================================================================= class Scoreboard(uvm_component): """ Clock activity scoreboard. """ CLOCKS = [ "pic_raddr_c1_clk", "pic_data_c1_clk", "pic_pri_c1_clk", "pic_int_c1_clk", ] IO_CLOCKS = [ # FIXME: "IO" clock gates are instanced along with gateway modules # inside a generate block. It appears that cocotb does not have access # to them. ] def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Got a change in clock override control if isinstance(item, ClockEnableItem): # Initially pass if self.passed is None: self.passed = True # Reject next clock state item got_it, it = self.port.try_get() assert got_it and isinstance(it, ClockStateItem) # Get next clock state item and process it got_it, it = self.port.try_get() assert got_it and isinstance(it, ClockStateItem) # Check clocks for clk in self.CLOCKS: if it.state[clk] != item.clk_en: self.passed = False self.logger.error( "Clock '{}' is {}toggling".format( clk, "not " if item.clk_en else "", ) ) for clk in self.IO_CLOCKS: if it.state[clk] != item.io_clk_en: self.passed = False self.logger.error( "IO clock '{}' is {}toggling".format( clk, "not " if item.io_clk_en else "", ) ) def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================= class TestSequence(uvm_sequence): """ A sequence which instructs a driver to enable/disable clock gating override """ async def body(self): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") # Disable overrides item = ClockEnableItem(0, 0) await self.start_item(item) await self.finish_item(item) # Wait await Timer(20 * period, "ns") # Enable clock override item = ClockEnableItem(1, 0) await self.start_item(item) await self.finish_item(item) # Wait await Timer(20 * period, "ns") # Disable overrides item = ClockEnableItem(0, 0) await self.start_item(item) await self.finish_item(item) # Wait await Timer(20 * period, "ns") # Enable clock override item = ClockEnableItem(0, 1) await self.start_item(item) await self.finish_item(item) # Wait await Timer(20 * period, "ns") # Disable overrides item = ClockEnableItem(0, 0) await self.start_item(item) await self.finish_item(item) # Wait await Timer(20 * period, "ns") # ============================================================================= class TestEnv(BaseEnv): """ Test environment """ def build_phase(self): super().build_phase() # Sequencers self.clken_seqr = uvm_sequencer("clken_seqr", self) # Clock enable driver and monitor self.clken_drv = ClkenDriver("clken_drv", self, uut=cocotb.top) self.clken_mon = ClkenMonitor("clken_mon", self, uut=cocotb.top) # Clock monitor self.clk_mon = ClockMonitor("clk_mon", self, uut=cocotb.top) # Add scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() self.clken_drv.seq_item_port.connect(self.clken_seqr.seq_item_export) self.clken_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.clk_mon.ap.connect(self.scoreboard.fifo.analysis_export) @pyuvm.test() class TestClockEnable(BaseTest): """ A test that checks forcing clock gates open """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TestSequence.create("stimulus") async def run(self): await self.seq.start(self.env.clken_seqr) ================================================ FILE: verification/block/pic/test_config.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from pyuvm import * from testbench import BaseEnv, BaseTest, BusReadItem, BusWriteItem, RegisterMap # ============================================================================= class TestSequence(uvm_sequence): """ A sequence of randomized register and content writes followed by randomized reads of them. """ def __init__(self, name): super().__init__(name) self.reg_map = RegisterMap() async def body(self): num_itr = ConfigDB().get(None, "", "TEST_ITERATIONS") max_pri = ConfigDB().get(None, "", "PIC_NUM_PRIORITIES") for i in range(num_itr): # Issue register writes names = list(self.reg_map.reg.keys()) random.shuffle(names) written = [] for name in names: reg = self.reg_map.reg[name] val = None if name == "mpiccfg": val = random.randint(0, 1) elif name.startswith("meipl"): val = random.randint(0, max_pri) elif name.startswith("meigwctrl"): val = random.randint(0, 3) # 2-bit combinations elif name.startswith("meie"): val = random.randint(0, 1) # 1-bit combinations if val is None: continue item = BusWriteItem(reg, val) await self.start_item(item) await self.finish_item(item) written.append(reg) # Issue register reads for the written ones random.shuffle(written) for reg in written: item = BusReadItem(reg) await self.start_item(item) await self.finish_item(item) class Scoreboard(uvm_component): """ A scoreboard that keeps track of data written to registers and compares it with data read afterwards. """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None self.reg_map = RegisterMap() self.reg_content = dict() def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): while self.port.can_get(): # Get an item got_item, item = self.port.try_get() assert got_item # Initially pass if self.passed is None: self.passed = True # Bus write if isinstance(item, BusWriteItem): self.reg_content[item.addr] = item.data # Bus read elif isinstance(item, BusReadItem): # Get register name reg_name = "0x{:08X}".format(item.addr) name = self.reg_map.adr.get(item.addr) if name is not None: reg_name += " '{}'".format(name) # No entry golden = self.reg_content.get(item.addr) if golden is None: self.logger.error("Register {} was not written".format(reg_name)) self.passed = False # Mismatch elif golden != item.data: self.logger.error( "Register {} content mismatch, is 0x{:08X} should be 0x{:08X}".format( reg_name, item.data, golden ) ) self.passed = False else: self.logger.debug( "Register {} ok, 0x{:08X}".format( reg_name, item.data, ) ) def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.reg_mon.ap.connect(self.scoreboard.fifo.analysis_export) @pyuvm.test() class TestConfig(BaseTest): """ A test for PIC configuration register access """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TestSequence.create("stimulus") async def run(self): await self.seq.start(self.env.reg_seqr) ================================================ FILE: verification/block/pic/test_pending.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import cocotb import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseEnv, BaseTest, BusReadItem, BusWriteItem, IrqItem, RegisterMap # ============================================================================= class TestSequence(uvm_sequence): def __init__(self, name): super().__init__(name) self.reg_seqr = ConfigDB().get(None, "", "REG_SEQR") self.irq_seqr = ConfigDB().get(None, "", "IRQ_SEQR") self.regs = RegisterMap() async def body(self): num_irq = ConfigDB().get(None, "", "PIC_NUM_INTERRUPTS") # Disable all interrupts for i in range(1, num_irq): reg = self.regs.reg["meie{}".format(i)] item = BusWriteItem(reg, 0) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Configure gateways for i in range(1, num_irq): reg = self.regs.reg["meigwctrl{}".format(i)] val = 0x2 # Edge, active-high item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Wait await ClockCycles(cocotb.top.clk, 4) # Randomize IRQ irqs = 0 while irqs == 0: for i in range(1, num_irq): if random.random() > 0.5: irqs |= 1 << i item = IrqItem(irqs) await self.irq_seqr.start_item(item) await self.irq_seqr.finish_item(item) # Read IRQ pending status register(s) num_meip = (num_irq + 31) // 32 for i in range(0, num_meip): reg = self.regs.reg["meip{}".format(i)] item = BusReadItem(reg) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # ============================================================================== class Scoreboard(uvm_component): def __init__(self, name, parent): super().__init__(name, parent) self.passed = None self.regs = RegisterMap() def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): irqs = 0 while self.port.can_get(): _, item = self.port.try_get() # Register read if isinstance(item, BusReadItem): # Get the reg name reg = self.regs.adr.get(item.addr) if not reg: self.logger.error("Unknown register address 0x{:08X}".format(item.addr)) self.passed = False continue # This is a meipX register if reg.startswith("meip") and reg[4] != "l": x = int(reg[4:]) # Initially pass if self.passed is None: self.passed = True # Check if the content matches current IRQ pending status mask = 0xFFFFFFFF << (32 * x) pend = item.data << (32 * x) if irqs & mask != pend: self.logger.error( f"{reg} value {item.data:032b} does not match IRQ state {irqs:032b}" ) self.passed = False continue # IRQ state elif isinstance(item, IrqItem): irqs = item.irqs def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Increase iteration count count = ConfigDB().get(None, "", "TEST_ITERATIONS") ConfigDB().set(None, "*", "TEST_ITERATIONS", count * 2) # Add scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.reg_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.irq_mon.ap.connect(self.scoreboard.fifo.analysis_export) @pyuvm.test() class TestPending(BaseTest): """ Test reporting of pending IRQs """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TestSequence.create("stimulus") async def run(self): count = ConfigDB().get(None, "", "TEST_ITERATIONS") for i in range(count): await self.seq.start() await self.do_reset() ================================================ FILE: verification/block/pic/test_prioritization.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import cocotb import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import ( BaseEnv, BaseTest, BusReadItem, BusWriteItem, ClaimItem, IrqItem, PrioLvlItem, PriorityPredictor, PrioThrItem, RegisterMap, ) # ============================================================================= class TestSequence(uvm_sequence): def __init__(self, name): super().__init__(name) self.reg_seqr = ConfigDB().get(None, "", "REG_SEQR") self.pri_seqr = ConfigDB().get(None, "", "PRI_SEQR") self.irq_seqr = ConfigDB().get(None, "", "IRQ_SEQR") self.regs = RegisterMap() async def body(self): num_irq = ConfigDB().get(None, "", "PIC_NUM_INTERRUPTS") max_pri = ConfigDB().get(None, "", "PIC_NUM_PRIORITIES") num_itr = ConfigDB().get(None, "", "TEST_ITERATIONS") ena_prob = ConfigDB().get(None, "", "TEST_IRQ_ENA_PROB") irq_prob = ConfigDB().get(None, "", "TEST_IRQ_REQ_PROB") # Basic PIC config item = BusWriteItem(self.regs.reg["mpiccfg"], random.randint(0, 1)) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) for i in range(num_itr): # Randomize priorities for i in range(1, num_irq): reg = self.regs.reg["meipl{}".format(i)] val = random.randint(0, max_pri) item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Randomize enables for i in range(1, num_irq): reg = self.regs.reg["meie{}".format(i)] val = int(random.random() < ena_prob) item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Configure gateways for i in range(1, num_irq): reg = self.regs.reg["meigwctrl{}".format(i)] val = 0x2 # Edge, active-high item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Randomize current priority and threshold lvl = random.randint(0, max_pri) thr = random.randint(0, max_pri) item = PrioLvlItem(lvl) await self.pri_seqr.start_item(item) await self.pri_seqr.finish_item(item) item = PrioThrItem(thr) await self.pri_seqr.start_item(item) await self.pri_seqr.finish_item(item) # Wait await ClockCycles(cocotb.top.clk, 4) # Randomize IRQ irqs = 0 while irqs == 0: for i in range(1, num_irq): if random.random() > irq_prob: irqs |= 1 << i item = IrqItem(irqs) await self.irq_seqr.start_item(item) await self.irq_seqr.finish_item(item) # Wait await ClockCycles(cocotb.top.clk, 2) # Clear IRQ item = IrqItem(0) await self.irq_seqr.start_item(item) await self.irq_seqr.finish_item(item) # Wait await ClockCycles(cocotb.top.clk, 4) # Clear pending gateways for i in range(1, num_irq): if irqs & (1 << i): reg = self.regs.reg["meigwclr{}".format(i)] val = 0 item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Wait await ClockCycles(cocotb.top.clk, 5) # ============================================================================== class Scoreboard(uvm_component): def __init__(self, name, parent): super().__init__(name, parent) self.passed = None self.predictor = PriorityPredictor(self.logger) self.regs = RegisterMap() def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): num_irq = ConfigDB().get(None, "", "PIC_NUM_INTERRUPTS") max_pri = ConfigDB().get(None, "", "PIC_NUM_PRIORITIES") pri_lvl = 0 pri_thr = 0 irqs = 0 claimid = 0 mexintpend = 0 mhwakeup = 0 while self.port.can_get(): _, item = self.port.try_get() # Register write if isinstance(item, BusWriteItem): # Get the reg name reg = self.regs.adr.get(item.addr) if not reg: self.logger.error("Unknown register address 0x{:08X}".format(item.addr)) self.passed = False continue if reg.startswith("meipl"): s = int(reg[5:]) self.predictor.irqs[s].priority = item.data if reg.startswith("meie"): s = int(reg[4:]) self.predictor.irqs[s].enabled = bool(item.data) if reg == "mpiccfg": self.predictor.inv_order = bool(item.data) # Priority level elif isinstance(item, PrioLvlItem): pri_lvl = item.prio # Priority threshold elif isinstance(item, PrioThrItem): pri_thr = item.prio # IRQ elif isinstance(item, IrqItem): # Mark triggered interrupts for i in range(1, num_irq): if item.irqs & (1 << i): self.predictor.irqs[i].triggered = True # Store requested irqs if item.irqs != 0: irqs = item.irqs # Interrupt claim elif isinstance(item, ClaimItem): claimid = item.claimid mexintpend = item.mexintpend mhwakeup = item.mhwakeup # Check only if IRQs were requested if not irqs: continue irqs = 0 # Initially pass if self.passed is None: self.passed = True # Predict the claim pred = self.predictor.predict() # Check if claimid != pred.id: self.logger.error( "Interrupt mismatch, is {} should be {}".format(claimid, pred.id) ) self.passed = False # Check if the interrupt is above the current priority level # and threshold. Check if it is signaled correctly. else: # Predict mexintpend if self.predictor.inv_order: pred_mexintpend = ( pred.id != 0 and pred.priority != max_pri and pred.priority < pri_thr and pred.priority < pri_lvl ) else: pred_mexintpend = ( pred.id != 0 and pred.priority != 0 and pred.priority > pri_thr and pred.priority > pri_lvl ) # Predict mhwakeup if self.predictor.inv_order: pred_mhwakeup = pred.id != 0 and pred.priority == 0 else: pred_mhwakeup = pred.id != 0 and pred.priority == max_pri # Check if pred_mexintpend != mexintpend: self.logger.error( "Signaling mismatch, mexintpend is {} should be {}. irq {}, meicurpl={}, meipt={}".format( bool(mexintpend), bool(pred_mexintpend), pred.id, pri_lvl, pri_thr, ) ) self.passed = False if pred_mhwakeup != mhwakeup: self.logger.error( "Signaling mismatch, mhwakeup is {} should be {}. irq {}, meicurpl={}, meipt={}".format( bool(mhwakeup), bool(pred_mhwakeup), pred.id, pri_lvl, pri_thr, ) ) self.passed = False # Clear triggers for i in range(1, num_irq): self.predictor.irqs[i].triggered = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.reg_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.pri_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.irq_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.claim_mon.ap.connect(self.scoreboard.fifo.analysis_export) @pyuvm.test() class TestPrioritization(BaseTest): """ """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TestSequence.create("stimulus") async def run(self): await self.seq.start() ================================================ FILE: verification/block/pic/test_reset.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import cocotb import pyuvm from testbench import BaseTest # ============================================================================= @pyuvm.test() class TestReset(BaseTest): """ A basic test that resets the DUT """ async def run(self): # Check state of DUT signals after reset state = { "mexintpend": 0, "mhwakeup": 0, "pl": 0, "claimid": 0, } for name, value in state.items(): signal = getattr(cocotb.top, name) assert signal.value == value, "{}={}, should be {}".format(name, signal.value, value) ================================================ FILE: verification/block/pic/test_servicing.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import cocotb import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import ( BaseEnv, BaseTest, BusReadItem, BusWriteItem, ClaimItem, IrqItem, PrioLvlItem, PriorityPredictor, PrioThrItem, RegisterMap, ) # ============================================================================= class TestSequence(uvm_sequence): def __init__(self, name): super().__init__(name) self.reg_seqr = ConfigDB().get(None, "", "REG_SEQR") self.pri_seqr = ConfigDB().get(None, "", "PRI_SEQR") self.irq_seqr = ConfigDB().get(None, "", "IRQ_SEQR") self.regs = RegisterMap() async def body(self): num_irq = ConfigDB().get(None, "", "PIC_NUM_INTERRUPTS") max_pri = ConfigDB().get(None, "", "PIC_NUM_PRIORITIES") num_itr = ConfigDB().get(None, "", "TEST_ITERATIONS") ena_prob = ConfigDB().get(None, "", "TEST_IRQ_ENA_PROB") # Basic PIC config item = BusWriteItem(self.regs.reg["mpiccfg"], 0) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) predictor = PriorityPredictor() enabled_irqs = list() for i in range(num_itr): # Randomize priorities for i in range(1, num_irq): reg = self.regs.reg["meipl{}".format(i)] val = random.randint(0, max_pri) predictor.irqs[i].priority = val item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Randomize enables for i in range(1, num_irq): reg = self.regs.reg["meie{}".format(i)] val = int(random.random() < ena_prob) predictor.irqs[i].enabled = val if val: enabled_irqs.append(i) item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Configure gateways for i in range(1, num_irq): reg = self.regs.reg["meigwctrl{}".format(i)] val = 0x2 # Edge, active-high item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) # Set interrupt threshold item = PrioThrItem(random.randint(0, max_pri)) await self.pri_seqr.start_item(item) await self.pri_seqr.finish_item(item) # Wait await ClockCycles(cocotb.top.clk, 4) # Request IRQs irqs = 0 for i in enabled_irqs: predictor.irqs[i].triggered = val irqs |= 1 << i item = IrqItem(irqs) await self.irq_seqr.start_item(item) await self.irq_seqr.finish_item(item) # Wait await ClockCycles(cocotb.top.clk, 2) # Clear IRQ item = IrqItem(0) await self.irq_seqr.start_item(item) await self.irq_seqr.finish_item(item) # Wait await ClockCycles(cocotb.top.clk, 4) # Mimic interrupt servicing for i in range(50): # Limit iterations # Predict the IRQ to be serviced irq = predictor.predict() if irq.id == 0: break # Begin servicing, set meicurpl item = PrioLvlItem(irq.priority) await self.pri_seqr.start_item(item) await self.pri_seqr.finish_item(item) # Servicing period await ClockCycles(cocotb.top.clk, 5) # Finish servicing, set meicurpl to 0 item = PrioLvlItem(0) await self.pri_seqr.start_item(item) await self.pri_seqr.finish_item(item) # Clear pending reg = self.regs.reg["meigwclr{}".format(irq.id)] val = 0 item = BusWriteItem(reg, val) await self.reg_seqr.start_item(item) await self.reg_seqr.finish_item(item) predictor.irqs[irq.id].triggered = False await ClockCycles(cocotb.top.clk, 4) # ============================================================================== class Scoreboard(uvm_component): def __init__(self, name, parent): super().__init__(name, parent) self.passed = None self.predictor = PriorityPredictor(self.logger) self.regs = RegisterMap() def build_phase(self): self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): num_irq = ConfigDB().get(None, "", "PIC_NUM_INTERRUPTS") pri_thr = 0 irq_order = [] while self.port.can_get(): _, item = self.port.try_get() # Register write if isinstance(item, BusWriteItem): # Get the reg name reg = self.regs.adr.get(item.addr) if not reg: self.logger.error("Unknown register address 0x{:08X}".format(item.addr)) self.passed = False continue if reg.startswith("meipl"): s = int(reg[5:]) self.predictor.irqs[s].priority = item.data if reg.startswith("meie"): s = int(reg[4:]) self.predictor.irqs[s].enabled = bool(item.data) # Priority threshold elif isinstance(item, PrioThrItem): pri_thr = item.prio # IRQ elif isinstance(item, IrqItem): # Nothing triggered if not item.irqs: continue # Mark triggered interrupts for i in range(1, num_irq): if item.irqs & (1 << i): self.predictor.irqs[i].triggered = True # Predict the order of interrupt servicing for i in range(50): # Limit iterations # Predict the IRQ to be serviced irq = self.predictor.predict() if irq.id == 0: break irq_order.append(irq.id) # Clear pending self.predictor.irqs[irq.id].triggered = False self.logger.debug("Interrupt order: {}".format(irq_order)) # Interrupt claim elif isinstance(item, ClaimItem): # Not waiting for any interrupt if not irq_order: continue # Initially pass if self.passed is None: self.passed = True self.logger.debug( "Servicing {}, mexintpend={}".format( item.claimid, item.mexintpend, ) ) # check id if item.claimid != irq_order[0]: self.logger.error( "Incorrect interrupt servicing order, claimed {} should be {}".format( item.claimid, irq_order[0] ) ) self.passed = False # mexintpend must be set if not item.mexintpend and item.claimpl > pri_thr: self.logger.error("Interrupt not reported to the core") self.passed = False # Remove the serviced id irq_order = irq_order[1:] # Check if all interrupts were services if irq_order: self.logger.error("Interrupts {} were not serviced".format(irq_order)) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class TestEnv(BaseEnv): def build_phase(self): super().build_phase() # Add scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): super().connect_phase() # Connect monitors self.reg_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.pri_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.irq_mon.ap.connect(self.scoreboard.fifo.analysis_export) self.claim_mon.ap.connect(self.scoreboard.fifo.analysis_export) @pyuvm.test() class TestServicing(BaseTest): """ """ def __init__(self, name, parent): super().__init__(name, parent, TestEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TestSequence.create("stimulus") async def run(self): await self.seq.start() ================================================ FILE: verification/block/pic/testbench.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import os import pyuvm from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge from pyuvm import * # ============================================================================== class RegisterMap: """ Map of PIC memory-mapped registers """ def __init__(self, max_irqs=32, base_addr=0xF00C0000): self.reg = dict() self.adr = dict() self.add_reg("mpiccfg", base_addr + 0x3000) for s in range(1, max_irqs): name = "meipl{}".format(s) addr = base_addr + 4 * s self.add_reg(name, addr) for x in range(0, max_irqs // 32): name = "meip{}".format(x) addr = base_addr + 0x1000 + 4 * x self.add_reg(name, addr) for s in range(1, max_irqs): name = "meie{}".format(s) addr = base_addr + 0x2000 + 4 * s self.add_reg(name, addr) for s in range(1, max_irqs): name = "meigwctrl{}".format(s) addr = base_addr + 0x4000 + 4 * s self.add_reg(name, addr) for s in range(1, max_irqs): name = "meigwclr{}".format(s) addr = base_addr + 0x5000 + 4 * s self.add_reg(name, addr) def add_reg(self, name, addr): self.reg[name] = addr self.adr[addr] = name # ============================================================================== class BusWriteItem(uvm_sequence_item): """ A generic data bus write request / response """ def __init__(self, addr, data): super().__init__("BusWriteItem") self.addr = addr self.data = data def randomize(self): pass class BusReadItem(uvm_sequence_item): """ A generic data bus read request / response """ def __init__(self, addr, data=None): super().__init__("BusReadItem") self.addr = addr self.data = data def randomize(self): pass class PrioLvlItem(uvm_sequence_item): def __init__(self, prio): super().__init__("PrioLvlItem") self.prio = prio class PrioThrItem(uvm_sequence_item): def __init__(self, prio): super().__init__("PrioThrItem") self.prio = prio class IrqItem(uvm_sequence_item): def __init__(self, irqs): super().__init__("IrqItem") self.irqs = irqs class ClaimItem(uvm_sequence_item): def __init__(self, claimid, claimpl, mexintpend, mhwakeup): super().__init__("ClaimItem") self.claimid = claimid self.claimpl = claimpl self.mexintpend = mexintpend self.mhwakeup = mhwakeup class WaitItem(uvm_sequence_item): """ A generic wait item. Used to instruct a driver to wait N cycles """ def __init__(self, cycles): super().__init__("WaitItem") self.cycles = cycles def randomize(self): pass # ============================================================================== def collect_signals(signals, uut, obj): """ Collects signal objects from UUT and attaches them to the given object """ for sig in signals: if hasattr(uut, sig): s = getattr(uut, sig) else: s = None logging.error("Module {} does not have a signal '{}'".format(str(uut), sig)) setattr(obj, sig, s) # ============================================================================== class RegisterBfm: """ A BFM for the PIC configuration (registers) interface. """ SIGNALS = [ "picm_rden", "picm_rdaddr", "picm_rd_data", "picm_wren", "picm_wraddr", "picm_wr_data", "picm_mken", ] def __init__(self, uut, clk): # Collect signals collect_signals(self.SIGNALS, uut, self) # Get the clock obj = getattr(uut, clk) setattr(self, "picm_clk", obj) async def read(self, addr): """ Reads a register """ await RisingEdge(self.picm_clk) self.picm_rdaddr.value = addr self.picm_rden.value = 1 self.picm_mken.value = 0 await RisingEdge(self.picm_clk) self.picm_rden.value = 0 await FallingEdge(self.picm_clk) data = self.picm_rd_data.value return data async def write(self, addr, data): """ Writes a register """ await RisingEdge(self.picm_clk) self.picm_wraddr.value = addr self.picm_wr_data.value = data self.picm_wren.value = 1 self.picm_mken.value = 0 await RisingEdge(self.picm_clk) self.picm_wren.value = 0 class RegisterDriver(uvm_driver): """ Configuration (register) interface driver """ def __init__(self, *args, **kwargs): self.bfm = kwargs["bfm"] del kwargs["bfm"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, BusWriteItem): await self.bfm.write(it.addr, it.data) elif isinstance(it, BusReadItem): it.data = await self.bfm.read(it.addr) elif isinstance(it, WaitItem): await ClockCycles(self.bfm.picm_clk) else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class RegisterMonitor(uvm_component): """ Configuration (register) interface monitor """ def __init__(self, *args, **kwargs): self.bfm = kwargs["bfm"] del kwargs["bfm"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: await RisingEdge(self.bfm.picm_clk) # Read if self.bfm.picm_rden.value: addr = int(self.bfm.picm_rdaddr.value) await FallingEdge(self.bfm.picm_clk) data = int(self.bfm.picm_rd_data.value) self.logger.debug("read 0x{:08X} -> 0x{:08X}".format(addr, data)) self.ap.write(BusReadItem(addr, data)) # Write if self.bfm.picm_wren.value: addr = int(self.bfm.picm_wraddr.value) data = int(self.bfm.picm_wr_data.value) self.logger.debug("write 0x{:08X} <- 0x{:08X}".format(addr, data)) self.ap.write(BusWriteItem(addr, data)) # ============================================================================== class PrioDriver(uvm_driver): """ A driver for priority and priority threshold inputs of the PIC """ SIGNALS = [ "meicurpl", "meipt", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, PrioLvlItem): self.meicurpl.value = it.prio elif isinstance(it, PrioThrItem): self.meipt.value = it.prio else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class PrioMonitor(uvm_component): """ A monitor for priority and priority threshold of the PIC """ SIGNALS = [ "clk", "meicurpl", "meipt", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) self.prev_meicurpl = None self.prev_meipt = None def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Even though the signals are not registered sample them on # rising clock edge await RisingEdge(self.clk) # Sample signals curr_meicurpl = int(self.meicurpl.value) curr_meipt = int(self.meipt.value) # Send an item in case of a change if self.prev_meicurpl != curr_meicurpl: self.ap.write(PrioLvlItem(curr_meicurpl)) if self.prev_meipt != curr_meipt: self.ap.write(PrioThrItem(curr_meipt)) self.prev_meicurpl = curr_meicurpl self.prev_meipt = curr_meipt # ============================================================================== class IrqDriver(uvm_driver): """ A driver for interrupt requests """ SIGNALS = [ "extintsrc_req", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, IrqItem): self.extintsrc_req.value = it.irqs else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() class IrqMonitor(uvm_component): """ A monitor for interrupt requests """ SIGNALS = [ "clk", "extintsrc_req", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) self.prev_irqs = None def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Sample signals await RisingEdge(self.clk) curr_irqs = int(self.extintsrc_req.value) # Send an item in case of a change if self.prev_irqs != curr_irqs: self.ap.write(IrqItem(curr_irqs)) self.prev_irqs = curr_irqs # ============================================================================== class ClaimMonitor(uvm_component): SIGNALS = [ "clk", "extintsrc_req", "picm_wren", "claimid", "pl", "mexintpend", "mhwakeup", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) self.prev_irqs = 0 self.prev_wren = 0 def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: # Sample control signals await RisingEdge(self.clk) irqs = int(self.extintsrc_req.value) wren = int(self.picm_wren.value) is_wren = wren and not self.prev_wren # Rising edge of wren is_irqs = irqs & ~self.prev_irqs # Rising edge of any IRQ if is_wren or is_irqs: # Sample signals after a delay to give PIC time to react. # It was observed that in the simulation that the wait must # be at least 3 clock cycles long. await ClockCycles(self.clk, 3) claimid = int(self.claimid.value) claimpl = int(self.pl.value) mexintpend = int(self.mexintpend.value) mhwakeup = int(self.mhwakeup.value) self.ap.write(ClaimItem(claimid, claimpl, mexintpend, mhwakeup)) self.prev_irqs = irqs self.prev_wren = wren # ============================================================================== class PriorityPredictor: class Irq: """ Interrupt request state """ def __init__(self, n): self.id = n self.priority = 0 self.enabled = False self.triggered = False def __str__(self): return "id={:3d} en={} pri={:2d} trg={}".format( self.id, int(self.enabled), self.priority, int(self.triggered), ) def __repr__(self): return str(self) def __init__(self, logger=None): self.inv_order = False self.irqs = {i: self.Irq(i) for i in range(1, 32)} self.logger = logger if self.logger is None: self.logger = uvm_root().logger def predict(self): # Dump IRQs self.logger.debug("IRQs:") keys = sorted(list(self.irqs)) for k in keys: self.logger.debug(" " + str(self.irqs[k])) # Filter only enabled and triggered irqs = {k: v for k, v in self.irqs.items() if v.enabled and v.triggered} # Get the highest priority pred = None for irq in irqs.values(): # Skip priority 0 or 15 if self.inv_order: if irq.priority == 15: continue else: if irq.priority == 0: continue # Find max priority and min id if pred is None: pred = irq else: if self.inv_order: if irq.priority < pred.priority: pred = irq else: if irq.priority > pred.priority: pred = irq if irq.priority == pred.priority: if irq.id < pred.id: pred = irq if pred is None: return self.Irq(0) self.logger.debug("pred:") self.logger.debug(" " + str(pred)) return pred # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "PIC_NUM_INTERRUPTS", 32) ConfigDB().set(None, "*", "PIC_NUM_PRIORITIES", 15) ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 50) ConfigDB().set(None, "*", "TEST_IRQ_ENA_PROB", 0.75) ConfigDB().set(None, "*", "TEST_IRQ_REQ_PROB", 0.90) # Sequencers self.reg_seqr = uvm_sequencer("reg_seqr", self) self.pri_seqr = uvm_sequencer("pri_seqr", self) self.irq_seqr = uvm_sequencer("irq_seqr", self) # Register interface bfm = RegisterBfm(cocotb.top, "clk") self.reg_drv = RegisterDriver("reg_drv", self, bfm=bfm) self.reg_mon = RegisterMonitor("reg_mon", self, bfm=bfm) # Current priority and priority threshold interface self.pri_drv = PrioDriver("pri_drv", self, uut=cocotb.top) self.pri_mon = PrioMonitor("pri_mon", self, uut=cocotb.top) # Interrupt request self.irq_drv = IrqDriver("irq_drv", self, uut=cocotb.top) self.irq_mon = IrqMonitor("irq_mon", self, uut=cocotb.top) # Interrupt claim monitor self.claim_mon = ClaimMonitor("claim_mon", self, uut=cocotb.top) ConfigDB().set(None, "*", "REG_SEQR", self.reg_seqr) ConfigDB().set(None, "*", "PRI_SEQR", self.pri_seqr) ConfigDB().set(None, "*", "IRQ_SEQR", self.irq_seqr) def connect_phase(self): self.reg_drv.seq_item_port.connect(self.reg_seqr.seq_item_export) self.pri_drv.seq_item_port.connect(self.pri_seqr.seq_item_export) self.irq_drv.seq_item_port.connect(self.irq_seqr.seq_item_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.free_clk.value = 0 cocotb.top.clk_override.value = 0 cocotb.top.io_clk_override.value = 0 cocotb.top.extintsrc_req.value = 0 cocotb.top.picm_rdaddr.value = 0 cocotb.top.picm_wraddr.value = 0 cocotb.top.picm_wr_data.value = 0 cocotb.top.picm_wren.value = 0 cocotb.top.picm_rden.value = 0 cocotb.top.picm_mken.value = 0 cocotb.top.meicurpl.value = 0 cocotb.top.meipt.value = 0 cocotb.top.scan_mode.value = 0 cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") self.start_clock("free_clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/pic_gw/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_configurable_gw VERILOG_SOURCES = \ $(SRCDIR)/el2_pic_ctrl.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/pic_gw/test_gateway.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import os import cocotb from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge # ============================================================================== async def start_clocks(dut): """ Starts DUT clocks """ # When VeeR is built in FPGA-optimized mode rawclk is used by rvdffs inside # the gateway. Otherwise the gw_clk is used. For testing start both of them. gw_clk = Clock(dut.gw_clk, 1, units="ns") rawclk = Clock(dut.rawclk, 1, units="ns") cocotb.start_soon(gw_clk.start(start_high=False)) cocotb.start_soon(rawclk.start(start_high=False)) # Enable cocotb.top.clken.value = 1 async def do_reset(dut): """ Resets the DUT """ await ClockCycles(dut.gw_clk, 2) dut.rst_l.value = 0 await ClockCycles(dut.gw_clk, 1) await FallingEdge(dut.gw_clk) dut.rst_l.value = 1 async def clear_pending(dut): """ Clears the pending interrupt flag of the tested module """ dut.meigwclr.value = 1 await ClockCycles(dut.gw_clk, 1) dut.meigwclr.value = 0 await ClockCycles(dut.gw_clk, 3) # ============================================================================== async def test_level(dut, pol): """ Tests level-sensitive interrupt """ # Default state dut.extintsrc_req.value = not pol # Level-sensitive dut.meigwctrl_type.value = 0 dut.meigwctrl_polarity.value = not pol # Reset await do_reset(dut) # Wait await ClockCycles(dut.gw_clk, 3) # The request should not be pending assert dut.extintsrc_req_config.value == 0 # Request an interrupt dut.extintsrc_req.value = pol await ClockCycles(dut.gw_clk, 3) # The request should be pending now assert dut.extintsrc_req_config.value == 1 # Clear the pending bit await clear_pending(dut) # The request should be still pending (level sensitive) assert dut.extintsrc_req_config.value == 1 # Cancel the request dut.extintsrc_req.value = not pol await ClockCycles(dut.gw_clk, 3) # The request should be still pending (latched state) # assert dut.extintsrc_req_config.value == 1 # FIXME: It appears that the gateway does not latch the trigger state # in level-sensitive mode but rather passes through the interrupt request # signal. assert dut.extintsrc_req_config.value == 0 # Clear the pending bit again await clear_pending(dut) # The request should not be pending now assert dut.extintsrc_req_config.value == 0 # Wait await ClockCycles(dut.gw_clk, 3) @cocotb.test() async def test_level_hi(dut): await start_clocks(dut) await test_level(dut, True) @cocotb.test() async def test_level_lo(dut): await start_clocks(dut) await test_level(dut, False) async def test_edge(dut, pol): """ Tests edge-sensitive interrupt """ # Default state dut.extintsrc_req.value = not pol # Edge-sensitive dut.meigwctrl_type.value = 1 dut.meigwctrl_polarity.value = not pol # Reset await do_reset(dut) # Wait await ClockCycles(dut.gw_clk, 3) # The request should not be pending assert dut.extintsrc_req_config.value == 0 # Request an interrupt dut.extintsrc_req.value = pol await ClockCycles(dut.gw_clk, 1) dut.extintsrc_req.value = not pol await ClockCycles(dut.gw_clk, 3) # The request should be pending now assert dut.extintsrc_req_config.value == 1 # Wait await ClockCycles(dut.gw_clk, 10) # The request should still be pending now assert dut.extintsrc_req_config.value == 1 # Clear the pending bit await clear_pending(dut) # The request should not be pending now assert dut.extintsrc_req_config.value == 0 # Wait await ClockCycles(dut.gw_clk, 3) @cocotb.test() async def test_edge_rising(dut): await start_clocks(dut) await test_edge(dut, True) # @cocotb.test() # TODO: Falling edge case is failing. Re-enable upon RTL fix async def test_edge_falling(dut): await start_clocks(dut) await test_edge(dut, False) async def test_edge_reset(dut, pol): """ Tests edge-sensitive interrupt """ # Default state dut.extintsrc_req.value = not pol # Edge-sensitive dut.meigwctrl_type.value = 1 dut.meigwctrl_polarity.value = not pol # Reset await do_reset(dut) # Wait await ClockCycles(dut.gw_clk, 3) # The request should not be pending assert dut.extintsrc_req_config.value == 0 # Request an interrupt dut.extintsrc_req.value = pol await ClockCycles(dut.gw_clk, 1) dut.extintsrc_req.value = not pol await ClockCycles(dut.gw_clk, 3) # The request should be pending now assert dut.extintsrc_req_config.value == 1 # Wait await ClockCycles(dut.gw_clk, 10) # Reset await do_reset(dut) # Wait await ClockCycles(dut.gw_clk, 3) # The request should not be pending now assert dut.extintsrc_req_config.value == 0 # Wait await ClockCycles(dut.gw_clk, 3) @cocotb.test() async def test_edge_rising_reset(dut): await start_clocks(dut) await test_edge_reset(dut, True) # @cocotb.test() # TODO: Falling edge case is failing. Re-enable upon RTL fix async def test_edge_falling_reset(dut): await start_clocks(dut) await test_edge_reset(dut, False) ================================================ FILE: verification/block/pmp/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_pmp_wrapper VERILOG_SOURCES = \ $(TEST_DIR)/el2_pmp_wrapper.sv \ $(SRCDIR)/el2_pmp.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/pmp/common.py ================================================ from random import randrange from pyuvm import ConfigDB, uvm_sequence from testbench import PMPCheckItem class BaseSequence(uvm_sequence): MAX_ADDR = 2**32 - 4 def __init__(self, name): super().__init__(name) self.pmp_regs = ConfigDB().get(None, "", "PMP_CSRS") self.pmp_seqr = ConfigDB().get(None, "", "PMP_SEQR") self.pmp_channels = ConfigDB().get(None, "", "PMP_CHANNELS") # Access (R, W, X) memory at a given address on all channels async def accessAtAddr(self, addr): for t in range(3): type = 1 << t for c in range(self.pmp_channels): item = PMPCheckItem(channel=c, addr=addr, type=type) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) # Try to access memory at random locations in a given address range async def randomAccessInAddrRange(self, start_addr, end_addr): addr = randrange(start_addr, end_addr, 4) await self.accessAtAddr(addr) # Access memory at a given address and at adjacent addresses async def checkRangeBoundary(self, addr): # Ensure access address is always aligned and doesn't extend 32 bits, # address is assumed to be inclusive so increment it by 1 initially. addr = min(self.MAX_ADDR, (addr + 1) & 0xFFFFFFFC) if addr >= 4: await self.accessAtAddr(addr - 4) await self.accessAtAddr(addr) if addr < self.MAX_ADDR: await self.accessAtAddr(addr + 4) ================================================ FILE: verification/block/pmp/config.vlt ================================================ `verilator_config lint_off -rule WIDTHTRUNC -file "*/el2_pmp_wrapper.sv" ================================================ FILE: verification/block/pmp/el2_pmp_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_pmp_wrapper import el2_pkg::*; #( parameter PMP_CHANNELS = 3, `include "el2_param.vh" ) ( input logic clk, // Top level clock input logic rst_l, // Reset input logic scan_mode, // Scan mode input [7:0] pmp_pmpcfg [pt.PMP_ENTRIES], input logic [31:0] pmp_pmpaddr[pt.PMP_ENTRIES], input logic [ 31:0] pmp_chan_addr[PMP_CHANNELS], input el2_pmp_type_pkt_t pmp_chan_type[PMP_CHANNELS], output logic [PMP_CHANNELS-1:0] pmp_chan_err ); logic pmp_chan_err_unpacked[PMP_CHANNELS]; el2_pmp_cfg_pkt_t pmp_pmpcfg_int [pt.PMP_ENTRIES]; for (genvar c = 0; c < PMP_CHANNELS; c++) begin assign pmp_chan_err[PMP_CHANNELS-1-c] = pmp_chan_err_unpacked[c]; end for (genvar e = 0; e < pt.PMP_ENTRIES; e++) begin assign pmp_pmpcfg_int[e].lock = pmp_pmpcfg[e][7]; assign pmp_pmpcfg_int[e].reserved = pmp_pmpcfg[e][6:5]; assign pmp_pmpcfg_int[e].mode = el2_pkg::el2_pmp_mode_pkt_t'(pmp_pmpcfg[e][4:3]); assign pmp_pmpcfg_int[e].execute = pmp_pmpcfg[e][2]; assign pmp_pmpcfg_int[e].write = pmp_pmpcfg[e][1]; assign pmp_pmpcfg_int[e].read= pmp_pmpcfg[e][0]; end // The PMP module el2_pmp pmp ( .pmp_chan_err(pmp_chan_err_unpacked), .pmp_pmpcfg(pmp_pmpcfg_int), .* ); endmodule ================================================ FILE: verification/block/pmp/test_address_matching.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 from pyuvm import ConfigDB, test from testbench import ( BaseEnv, BaseTest, PMPWriteAddrCSRItem, PMPWriteCfgCSRItem, getDecodedEntryCfg, ) from common import BaseSequence pmp_configurations = [ { # 0 - Entry locked but disabled, address 0x1000 "pmpcfg": 0b10000000, "pmpaddr": (0x1000 >> 2), }, { # 1 - Entry locked, allow RWX, TOR, address range 0x1000-0x1FFF "pmpcfg": 0b10001111, "pmpaddr": (0x2000 >> 2), }, { # 2 - Entry locked, allow R, TOR, address range 0x2000-0x3FFF "pmpcfg": 0b10001001, "pmpaddr": (0x4000 >> 2), }, { # 3 - Entry locked, allow X, TOR, address range 0x4000-0xFFFF "pmpcfg": 0b10001100, "pmpaddr": (0x10000 >> 2), }, { # 4 - Entry locked, allow W, TOR, address range 0x10000-0x1FFFF "pmpcfg": 0b10001010, "pmpaddr": (0x20000 >> 2), }, { # 5 - Entry unlocked, allow none, TOR, address range 0x20000-0xFFFFFFFF "pmpcfg": 0b00001000, "pmpaddr": (0x100000000 >> 2), }, { # 6 - Entry locked, allow none, TOR, address range 0xFFFFFFFF-0x10000 "pmpcfg": 0b10001000, "pmpaddr": (0x20000 >> 2), }, { # 7 - Entry locked, allow RWX, NA4, address range 0x20000-0x20003 "pmpcfg": 0b10010111, "pmpaddr": (0x20000 >> 2), }, { # 8 - Entry locked, allow none, NA4, address range 0x30000-0x30003 "pmpcfg": 0b10010000, "pmpaddr": (0x30000 >> 2), }, { # 9 - Entry locked, allow none, NAPOT, address range 0x40000-0x5FFFF "pmpcfg": 0b10011000, "pmpaddr": (0x57FFF >> 2), }, { # 10 - Entry locked, allow RW, NAPOT, address range 0x24000-0x25FFF "pmpcfg": 0b10011011, "pmpaddr": (0x257FF >> 2), }, { # 11 - Entry locked, allow X, NAPOT, address range 0x26000-0x26FFF "pmpcfg": 0b10011100, "pmpaddr": (0x26BFF >> 2), }, { # 12 - Entry locked, allow RW, NAPOT, address range 0x26000-0x26FFF "pmpcfg": 0b10011011, "pmpaddr": (0x26BFF >> 2), }, ] # ============================================================================= class TestSequence(BaseSequence): def __init__(self, name): super().__init__(name) async def body(self): test_iterations = ConfigDB().get(None, "", "TEST_ITERATIONS") pmp_entries = ConfigDB().get(None, "", "PMP_ENTRIES") # Ensure to not use more configurations than PMP entries assert len(pmp_configurations) <= pmp_entries # Configure PMP entries for i, cfg in enumerate(pmp_configurations): item = PMPWriteAddrCSRItem(index=i, pmpaddr=cfg["pmpaddr"]) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) for i, cfg in enumerate(pmp_configurations): item = PMPWriteCfgCSRItem(index=i, pmpcfg=cfg["pmpcfg"]) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) # Check boundaries and few random addresses of each PMP entry for i in range(len(pmp_configurations)): start_addr, end_addr = getDecodedEntryCfg(self.pmp_regs, i, range_only=True) await self.checkRangeBoundary(start_addr) # Access up to 10 random memory cells accesses = min((end_addr - start_addr) // 4, 10) if start_addr != end_addr: for _ in range(accesses): await self.randomAccessInAddrRange(start_addr, end_addr) await self.checkRangeBoundary(end_addr) # In the end check accesses at random memory locations for _ in range(test_iterations): await self.randomAccessInAddrRange(0x00000000, 0xFFFFFFFF) # ============================================================================== @test() class TestAddressMatching(BaseTest): """ This test provides a sequence that checks behaviour for different address matching schemes like: - Disabled entries - Top of range with lower boundary than previous entry - Top of range with higher boundary than previous entry - Unlocked entry that "forbids" access - Different permissions restrictions - Different configurations with interlacing address ranges """ def __init__(self, name, parent): super().__init__(name, parent, BaseEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TestSequence.create("stimulus") async def run(self): await self.seq.start() ================================================ FILE: verification/block/pmp/test_multiple_configs.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 from pyuvm import ConfigDB, test from testbench import BaseEnv, BaseTest, PMPWriteAddrCSRItem, PMPWriteCfgCSRItem from common import BaseSequence LOWER_BOUNDARY = 0x00000 UPPER_BOUNDARY = 0x20000 pmp_configurations = [ { # 0 - Entry locked, allow none, TOR, address range 0x00000-0x0FFFF "pmpcfg": 0b10001000, "pmpaddr": (0x10000 >> 2), }, { # 1 - Entry locked, but disabled, address 0x01000 "pmpcfg": 0b10000000, "pmpaddr": (0x01000 >> 2), }, { # 2 - Entry locked, allow RWX, TOR, address range 0x01000-0x0FFFF "pmpcfg": 0b10001111, "pmpaddr": (0x10000 >> 2), }, { # 3 - Entry unlocked, address 0x01000 "pmpcfg": 0b00000000, "pmpaddr": (0x01000 >> 2), }, { # 4 - Entry locked, allow R, TOR, address range 0x01000-0x1FFFF "pmpcfg": 0b10001001, "pmpaddr": (0x20000 >> 2), }, { # 5 - Entry unlocked, address 0x01000 "pmpcfg": 0b00000000, "pmpaddr": (0x01000 >> 2), }, { # 6 - Entry locked, allow W, TOR, address range 0x01000-0x1FFFF "pmpcfg": 0b10001010, "pmpaddr": (0x20000 >> 2), }, { # 7 - Entry unlocked, address 0x01000 "pmpcfg": 0b00000000, "pmpaddr": (0x01000 >> 2), }, { # 8 - Entry locked, allow X, TOR, address range 0x01000-0x1FFFF "pmpcfg": 0b10001100, "pmpaddr": (0x20000 >> 2), }, ] # ============================================================================= class TestSequence(BaseSequence): def __init__(self, name): super().__init__(name) async def body(self): test_iterations = ConfigDB().get(None, "", "TEST_ITERATIONS") pmp_entries = ConfigDB().get(None, "", "PMP_ENTRIES") # Ensure to not use more configurations than PMP entries assert len(pmp_configurations) <= pmp_entries # Configure PMP entries for i, cfg in enumerate(pmp_configurations): item = PMPWriteAddrCSRItem(index=i, pmpaddr=cfg["pmpaddr"]) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) for i, cfg in enumerate(pmp_configurations): item = PMPWriteCfgCSRItem(index=i, pmpcfg=cfg["pmpcfg"]) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) await self.checkRangeBoundary(LOWER_BOUNDARY) for _ in range(test_iterations): await self.randomAccessInAddrRange(LOWER_BOUNDARY, UPPER_BOUNDARY) await self.checkRangeBoundary(UPPER_BOUNDARY) # ============================================================================== @test() class TestMultipleConfigs(BaseTest): """ This test provides a sequence that checks behaviour for multiple PMP configurations appplying to the same address ranges. """ def __init__(self, name, parent): super().__init__(name, parent, BaseEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TestSequence.create("stimulus") async def run(self): await self.seq.start() ================================================ FILE: verification/block/pmp/test_xwr_access.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 from pyuvm import ConfigDB, test, uvm_sequence from testbench import ( BaseEnv, BaseTest, PMPCheckItem, PMPWriteAddrCSRItem, PMPWriteCfgCSRItem, ) # ============================================================================= class TestSequence(uvm_sequence): def __init__(self, name): super().__init__(name) self.pmp_seqr = ConfigDB().get(None, "", "PMP_SEQR") async def body(self): pmp_entries = ConfigDB().get(None, "", "PMP_ENTRIES") pmp_channels = ConfigDB().get(None, "", "PMP_CHANNELS") # Configure entries to all possible XWR configurations # Use TOR address matching for simplicity # 0b10001000 # - bit 7 - Locked status (1 is locked) # - bits 6-5 - Reserved (always 0) # - bits 4-3 - Address Matching configuration (01 is TOR) # - bit 2 - Execute permission # - bit 1 - Write permission # - bit 0 - Read permission MAX_XWR_CONFIGS = 8 for i in range(MAX_XWR_CONFIGS): addr = ((i + 1) * 0x1000) >> 2 item = PMPWriteAddrCSRItem(index=i, pmpaddr=addr) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) for i in range(MAX_XWR_CONFIGS): cfg = 0b10001000 + i item = PMPWriteCfgCSRItem(index=i, pmpcfg=cfg) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) # Check all possible access variants on configured entries for i in range(pmp_channels): channel = i # Set type to each of 3 available (R or W or X) for j in range(3): type = 1 << j for k in range(pmp_entries): # Set address somewhere in the 0x1000 wide entry addr = (0x200 + (k * 0x1000)) >> 2 item = PMPCheckItem(channel, addr, type) await self.pmp_seqr.start_item(item) await self.pmp_seqr.finish_item(item) # ============================================================================== @test() class TestXWRAccess(BaseTest): """ This test configures few registers to covers or possible variants of RWX access permissions and then checks if they are properly checked. """ def __init__(self, name, parent): super().__init__(name, parent, BaseEnv) def end_of_elaboration_phase(self): super().end_of_elaboration_phase() self.seq = TestSequence.create("stimulus") async def run(self): await self.seq.start() ================================================ FILE: verification/block/pmp/testbench.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import os from cocotb.binary import BinaryValue from cocotb.clock import Clock from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge from pyuvm import * # ============================================================================== ACCESS_TYPE = { 0b001: "R", 0b010: "W", 0b100: "X", } class RegisterMap: def __init__(self, pmp_entries): self.reg = dict() for i in range(pmp_entries): name = "pmpcfg{}".format(i) self.reg[name] = BinaryValue(value=0, bigEndian=False, n_bits=8) name = "pmpaddr{}".format(i) self.reg[name] = BinaryValue(value=0, bigEndian=False, n_bits=32) def getDecodedEntryCfg(regs, index, range_only=False): """ """ pmpcfg = regs.reg["pmpcfg{}".format(index)] pmpaddr = regs.reg["pmpaddr{}".format(index)] # bits 0-2, (R, W, X) permissions = {"R": pmpcfg[0].integer, "W": pmpcfg[1].integer, "X": pmpcfg[2].integer} address_matching = pmpcfg[4:3].integer locked = pmpcfg[7].integer if index: start_address = regs.reg["pmpaddr{}".format(index - 1)].integer << 2 else: start_address = 0 if address_matching == 0: # Entry diabled if range_only: end_address = pmpaddr.integer << 2 return start_address, end_address else: return None elif address_matching == 1: # Top of range end_address = pmpaddr.integer << 2 if start_address > end_address: if range_only: return start_address, end_address else: return None elif address_matching == 2: # Naturally aligned four-byte region end_address = (pmpaddr.integer << 2) + 4 elif address_matching == 3: # Naturally aligned power-of-two region, >=8 bytes napot = 3 start_address = pmpaddr for i in range(len(pmpaddr)): if pmpaddr[i].integer == 1: start_address[i].value = 0 napot += 1 else: continue start_address = start_address.integer << 2 end_address = start_address + 2**napot # PMP upper address bundary is non-inclusive end_address -= 1 if range_only: return start_address, end_address else: return start_address, end_address, permissions, locked # ============================================================================== class PMPWriteCfgCSRItem(uvm_sequence_item): def __init__(self, index, pmpcfg): super().__init__("PMPWriteCfgCSRItem") self.index = index self.pmpcfg = pmpcfg class PMPWriteAddrCSRItem(uvm_sequence_item): def __init__(self, index, pmpaddr): super().__init__("PMPWriteAddrCSRItem") self.index = index self.pmpaddr = pmpaddr class PMPCheckItem(uvm_sequence_item): def __init__(self, channel, addr, type, err=None): super().__init__("PMPCheckItem") self.channel = channel self.addr = addr self.type = type self.err = err # ============================================================================== def collect_signals(signals, uut, obj): """ Collects signal objects from UUT and attaches them to the given object """ for sig in signals: if hasattr(uut, sig): s = getattr(uut, sig) else: s = None logging.error("Module {} does not have a signal '{}'".format(str(uut), sig)) setattr(obj, sig, s) # ============================================================================== class PMPDriver(uvm_driver): SIGNALS = [ "clk", # CSRs "pmp_pmpcfg", "pmp_pmpaddr", # PMP logic "pmp_chan_addr", "pmp_chan_type", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) self.regs = ConfigDB().get(None, "", "PMP_CSRS") # Collect signals collect_signals(self.SIGNALS, uut, self) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, PMPWriteAddrCSRItem): self.pmp_pmpaddr[it.index].value = it.pmpaddr self.regs.reg["pmpaddr{}".format(it.index)].integer = it.pmpaddr elif isinstance(it, PMPWriteCfgCSRItem): self.pmp_pmpcfg[it.index].value = it.pmpcfg self.regs.reg["pmpcfg{}".format(it.index)].integer = it.pmpcfg elif isinstance(it, PMPCheckItem): self.pmp_chan_addr[it.channel].value = it.addr self.pmp_chan_type[it.channel].value = it.type else: raise RuntimeError("Unknown item '{}'".format(type(it))) await ClockCycles(self.clk, 1) self.seq_item_port.item_done() class PMPMonitor(uvm_component): SIGNALS = [ "clk", # CSRs "pmp_pmpcfg", "pmp_pmpaddr", # PMP logic "pmp_chan_addr", "pmp_chan_type", "pmp_chan_err", ] def __init__(self, *args, **kwargs): uut = kwargs["uut"] del kwargs["uut"] super().__init__(*args, **kwargs) collect_signals(self.SIGNALS, uut, self) self.pmp_channels = ConfigDB().get(None, "", "PMP_CHANNELS") self.pmp_entries = ConfigDB().get(None, "", "PMP_ENTRIES") def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: await RisingEdge(self.clk) # Check all PMP channels for i in range(self.pmp_channels): access_addr = int(self.pmp_chan_addr[i].value) access_type = int(self.pmp_chan_type[i].value) access_err = int(self.pmp_chan_err.value[i]) self.ap.write(PMPCheckItem(i, access_addr, access_type, access_err)) # ============================================================================== class Scoreboard(uvm_component): def build_phase(self): self.passed = True self.fifo = uvm_tlm_analysis_fifo("fifo", self) self.port = uvm_get_port("port", self) self.regs = ConfigDB().get(None, "", "PMP_CSRS") def connect_phase(self): self.port.connect(self.fifo.get_export) def check_phase(self): while self.port.can_get(): _, item = self.port.try_get() if isinstance(item, PMPCheckItem): addr = item.addr type = item.type chan = item.channel err = item.err type_str = ACCESS_TYPE.get(type, "UNKNOWN ({})".format(type)) if type_str not in ACCESS_TYPE.values(): self.logger.debug( "Unknown access type ({}), probably checking channel that doesn't request access.".format( type ) ) continue # Check if address range can be matched to any PMP entry entry_permissions = None for i in range(len(self.regs.reg) // 2): entry = getDecodedEntryCfg(self.regs, i) if entry is not None: pmp_start_addr, pmp_end_addr, permissions, locked = entry else: continue # Check if entry address range matches channel address if addr in range(pmp_start_addr, pmp_end_addr): if locked: # If entry is locked, save it for permission checks entry_permissions = permissions break log_msg = "PMPCheckItem: Validating access 0x{:08x}, type={} ({}), channel={}, error={}".format( addr, type, type_str, chan, err ) if entry_permissions is None: # If address range was not matched, ensure that error is not raised if err: self.logger.error("Error asserted when no entry was matched!") self.logger.debug(log_msg) self.passed = False else: # If address range was matched, compare permissions to the command type for op in ACCESS_TYPE.values(): if type_str == op and not (entry_permissions[op] ^ err): self.logger.error("Unexpected error state on access request!") self.logger.debug(log_msg) self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config pmp_entries = 16 ConfigDB().set(None, "*", "PMP_ENTRIES", pmp_entries) ConfigDB().set(None, "*", "PMP_CHANNELS", 3) ConfigDB().set(None, "*", "PMP_GRANULARITY", 0) ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 100) # PMP Registers self.regs = RegisterMap(pmp_entries) ConfigDB().set(None, "*", "PMP_CSRS", self.regs) # Sequencers self.pmp_seqr = uvm_sequencer("pmp_seqr", self) # PMP interface self.pmp_drv = PMPDriver("pmp_drv", self, uut=cocotb.top) self.pmp_mon = PMPMonitor("pmp_mon", self, uut=cocotb.top) # Add scoreboard self.scoreboard = Scoreboard("scoreboard", self) ConfigDB().set(None, "*", "PMP_SEQR", self.pmp_seqr) def connect_phase(self): self.pmp_drv.seq_item_port.connect(self.pmp_seqr.seq_item_export) self.pmp_mon.ap.connect(self.scoreboard.fifo.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def run_phase(self): self.raise_objection() cocotb.top.scan_mode.value = 0 cocotb.top.pmp_chan_addr.value = [0, 0, 0] cocotb.top.pmp_chan_type.value = [0, 0, 0] self.start_clock("clk") cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 await self.run() await ClockCycles(cocotb.top.clk, 2) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/pmp_random/Makefile ================================================ null := space := $(null) # comma := , TEST_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) SRCDIR := $(abspath $(TEST_DIR)../../../../design) TEST_FILES = $(sort $(wildcard test_*.py)) MODULE ?= $(subst $(space),$(comma),$(subst .py,,$(TEST_FILES))) TOPLEVEL = el2_pmp_wrapper PMP_TEST := 1 VERILOG_SOURCES = \ $(TEST_DIR)/el2_pmp_wrapper.sv \ $(SRCDIR)/el2_pmp.sv include $(TEST_DIR)/../common.mk ================================================ FILE: verification/block/pmp_random/config.vlt ================================================ `verilator_config lint_off -rule WIDTHTRUNC -file "*/el2_pmp_wrapper.sv" ================================================ FILE: verification/block/pmp_random/el2_pmp_wrapper.sv ================================================ // Copyright (c) 2023 Antmicro // SPDX-License-Identifier: Apache-2.0 module el2_pmp_wrapper import el2_pkg::*; #( parameter PMP_CHANNELS = 3, `include "el2_param.vh" ) ( input logic clk, // Top level clock input logic rst_l, // Reset input logic scan_mode, // Scan mode input [7:0] pmp_pmpcfg [pt.PMP_ENTRIES], input logic [31:0] pmp_pmpaddr[pt.PMP_ENTRIES], input logic [ 31:0] pmp_chan_addr[PMP_CHANNELS], input el2_pmp_type_pkt_t pmp_chan_type[PMP_CHANNELS], output logic [PMP_CHANNELS-1:0] pmp_chan_err ); logic pmp_chan_err_unpacked[PMP_CHANNELS]; el2_pmp_cfg_pkt_t pmp_pmpcfg_int [pt.PMP_ENTRIES]; for (genvar c = 0; c < PMP_CHANNELS; c++) begin assign pmp_chan_err[PMP_CHANNELS-1-c] = pmp_chan_err_unpacked[c]; end for (genvar e = 0; e < pt.PMP_ENTRIES; e++) begin assign pmp_pmpcfg_int[e].lock = pmp_pmpcfg[e][7]; assign pmp_pmpcfg_int[e].reserved = pmp_pmpcfg[e][6:5]; assign pmp_pmpcfg_int[e].mode = el2_pkg::el2_pmp_mode_pkt_t'(pmp_pmpcfg[e][4:3]); assign pmp_pmpcfg_int[e].execute = pmp_pmpcfg[e][2]; assign pmp_pmpcfg_int[e].write = pmp_pmpcfg[e][1]; assign pmp_pmpcfg_int[e].read= pmp_pmpcfg[e][0]; end // The PMP module el2_pmp pmp ( .pmp_chan_err(pmp_chan_err_unpacked), .pmp_pmpcfg(pmp_pmpcfg_int), .* ); endmodule ================================================ FILE: verification/block/pmp_random/test_pmp_random.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import random import pyuvm from cocotb.triggers import ClockCycles from pyuvm import * from testbench import BaseTest, InputItem # ============================================================================= class PMPRandomLegalSequence(uvm_sequence): """ """ def __init__(self, name): super().__init__(name) def legalize_pmpcfg(self, item): """ Leave only A, X and R fields as any combination of them is legal and does not influence PMPADDR access. Setting L would interfere with the test. """ mask = 0b00011101 item.cfg &= (mask << 24) | (mask << 16) | (mask << 8) | mask def legalize_pmpaddr(self, item): """ Mask out two MSBs """ item.pmp_addr &= 0x3FFFFFFF async def body(self): # Run count = ConfigDB().get(None, "", "TEST_ITERATIONS") for i in range(count): item = InputItem() item.randomize() self.legalize_pmpaddr(item) self.legalize_pmpcfg(item) await self.start_item(item) await self.finish_item(item) @pyuvm.test() class TestRandomPMP(BaseTest): def end_of_elaboration_phase(self): super().end_of_elaboration_phase() count = ConfigDB().get(None, "", "TEST_ITERATIONS") self.seq = [PMPRandomLegalSequence("stimulus") for i in range(count)] async def run(self): for seq in self.seq: await seq.start(self.env.pmp_wr_seqr) ================================================ FILE: verification/block/pmp_random/testbench.py ================================================ # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 import copy import math import os import random import struct import pyuvm from cocotb.binary import BinaryValue from cocotb.clock import Clock from cocotb.triggers import ( ClockCycles, Event, FallingEdge, First, Lock, RisingEdge, Timer, ) from cocotb.types import Array, Range from pyuvm import * # ============================================================================== NONE = 0x0 READ = 0x1 WRITE = 0x2 EXEC = 0x4 # ============================================================================== class InputItem(uvm_sequence_item): """ PMP input item """ RANGE = 16 def __init__(self, cfg=0, entry=0, pmp_addr=0, chan_addr=0, chan_type=0, chan=0, chan_err=0): super().__init__("InputItem") self.cfg = cfg self.entry = entry self.pmp_addr = pmp_addr self.chan = chan self.chan_addr = chan_addr self.chan_type = chan_type self.chan_err = chan_err def randomize(self): """ Randomize cfg and addresses """ self.cfg = random.randint(0, 0xFF) self.entry = random.randint(0, 63) self.pmp_addr = random.randint(0, 0xFFFFFFFF) self.chan = random.randint(0, 2) self.chan_addr = random.randint(0, 0xFFFFFFFF) self.chan_type = random.randint(0, 3) # ============================================================================== class PMPWriteDriver(uvm_driver): """ PMP CSR write port driver driver """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) async def run_phase(self): while True: it = await self.seq_item_port.get_next_item() if isinstance(it, InputItem): await RisingEdge(self.dut.clk) self.dut.pmp_pmpcfg[it.entry].value = it.cfg self.dut.pmp_pmpaddr[it.entry].value = it.pmp_addr self.dut.pmp_chan_addr[it.chan].value = it.chan_addr self.dut.pmp_chan_type[it.chan].value = it.chan_type else: raise RuntimeError("Unknown item '{}'".format(type(it))) self.seq_item_port.item_done() # ============================================================================== class WriteMonitor(uvm_component): """ Monitor for CSR write inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: await RisingEdge(self.dut.clk) cfg = self.dut.pmp_pmpcfg.value pmp_addr = self.dut.pmp_pmpaddr.value chan_addr = self.dut.pmp_chan_addr.value chan_type = self.dut.pmp_chan_type item = InputItem(cfg=cfg, pmp_addr=pmp_addr, chan_addr=chan_addr, chan_type=chan_type) self.ap.write(item) class ReadMonitor(uvm_component): """ Monitor for CSR read inputs """ def __init__(self, *args, **kwargs): self.dut = kwargs["dut"] del kwargs["dut"] super().__init__(*args, **kwargs) def build_phase(self): self.ap = uvm_analysis_port("ap", self) async def run_phase(self): while True: await RisingEdge(self.dut.clk) chan_err = self.dut.pmp_chan_err item = InputItem(chan_err=chan_err) self.ap.write(item) # ============================================================================== class Scoreboard(uvm_component): """ PMP dec ctl scoreboard """ def __init__(self, name, parent): super().__init__(name, parent) self.passed = None def build_phase(self): self.fifo_inp = uvm_tlm_analysis_fifo("fifo_inp", self) self.fifo_out = uvm_tlm_analysis_fifo("fifo_out", self) self.port_inp = uvm_get_port("port_inp", self) self.port_out = uvm_get_port("port_out", self) def connect_phase(self): self.port_inp.connect(self.fifo_inp.get_export) self.port_out.connect(self.fifo_out.get_export) def check_phase(self): self.passed = None # Get item pairs while True: got_inp, item_inp = self.port_inp.try_get() got_out, item_out = self.port_out.try_get() if not got_inp and got_out: self.logger.error("No input item for output item") self.passed = False break if got_inp and not got_out: self.logger.error("No output item for input item") self.passed = False break if not got_inp and not got_out: break if self.passed is None: self.passed = True # we should never hit PMP error in this test if int(item_inp.chan_err) != 0: self.logger.error("Got PMP Error") self.passed = False def final_phase(self): if not self.passed: self.logger.critical("{} reports a failure".format(type(self))) assert False # ============================================================================== class BaseEnv(uvm_env): """ Base PyUVM test environment """ def build_phase(self): # Config ConfigDB().set(None, "*", "TEST_CLK_PERIOD", 1) ConfigDB().set(None, "*", "TEST_ITERATIONS", 200) # Sequencers self.pmp_wr_seqr = uvm_sequencer("pmp_wr_seqr", self) # Drivers self.pmp_wr_drv = PMPWriteDriver("pmp_wr_drv", self, dut=cocotb.top) # Monitors self.wr_mon = WriteMonitor("wr_mon", self, dut=cocotb.top) self.rd_mon = ReadMonitor("rd_mon", self, dut=cocotb.top) # Scoreboard self.scoreboard = Scoreboard("scoreboard", self) def connect_phase(self): self.pmp_wr_drv.seq_item_port.connect(self.pmp_wr_seqr.seq_item_export) self.wr_mon.ap.connect(self.scoreboard.fifo_inp.analysis_export) self.rd_mon.ap.connect(self.scoreboard.fifo_out.analysis_export) # ============================================================================== class BaseTest(uvm_test): """ Base test for the module """ def __init__(self, name, parent, env_class=BaseEnv): super().__init__(name, parent) self.env_class = env_class # Synchronize pyuvm logging level with cocotb logging level. Unclear # why it does not happen automatically. level = logging.getLevelName(os.environ.get("COCOTB_LOG_LEVEL", "INFO")) uvm_report_object.set_default_logging_level(level) def build_phase(self): self.env = self.env_class("env", self) def start_clock(self, name): period = ConfigDB().get(None, "", "TEST_CLK_PERIOD") sig = getattr(cocotb.top, name) clock = Clock(sig, period, units="ns") cocotb.start_soon(clock.start(start_high=False)) async def do_reset(self): cocotb.top.rst_l.value = 0 await ClockCycles(cocotb.top.clk, 2) await FallingEdge(cocotb.top.clk) cocotb.top.rst_l.value = 1 async def run_phase(self): self.raise_objection() # Start clocks self.start_clock("clk") # Issue reset await self.do_reset() # Wait some cycles await ClockCycles(cocotb.top.clk, 2) # Run the actual test await self.run() # Wait some cycles await ClockCycles(cocotb.top.clk, 10) self.drop_objection() async def run(self): raise NotImplementedError() ================================================ FILE: verification/block/pyproject.toml ================================================ # Copyright (C) 2023 Antmicro # SPDX-License-Identifier: Apache-2.0 [tool.black] line-length = 100 exclude = ''' ( /( | \.git | \.gitignore | \.gitmodules | \.github | \.nox | \.pytest_cache | __pycache__ | venv )/ | docs/source/conf.py ) ''' [tool.isort] profile = "black" multi_line_output = 3 ================================================ FILE: verification/block/requirements.txt ================================================ cocotb==1.8.0 cocotb-bus==0.2.1 cocotb-coverage==1.1.0 cocotb-test==0.2.4 pytest==7.4.1 pytest-html==3.2.0 pytest-timeout==2.1.0 pytest-md==0.2.0 pyuvm==2.9.1 scipy==1.13.1 ================================================ FILE: verification/test_debug/test_debug.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: BSD-2-Clause import pytest import subprocess class TestDebug(): def test_debug(self): print("This test returns true") assert True == True ================================================ FILE: verification/top/README.md ================================================ # Verification The verification directory contains [pyuvm](https://github.com/pyuvm/pyuvm) tests, which rely on [cocotb](https://github.com/cocotb/cocotb) library. ## Setup In order to run the tests, create a python virtual environment. Verilator is used as a backend simulator and must be present in the system. ### Clone repository Remember to set the `RV_ROOT` environment variable, which is required to generate VeeR-EL2 Core configuration files. git clone --recurse-submodules git@github.com:chipsalliance/Cores-VeeR-EL2.git cd Cores-Veer-EL2 export RV_ROOT=$(pwd) ### Prepare python virtual environment cd $RV_ROOT/verification/top python -m venv venv source venv/bin/activate pip install -r requirements.txt ### Install Verilator Installation instructions are available in the Verilator's User Guide: https://veripool.org/guide/latest/install.html ## Tests Each PyUVM test can be either run from a pytest wrapper or directly from a Makefile. The wrapper is placed to provide easier CI integration, HTML reports and Markdown summaries in job descriptions on GitHub. The Makefile execution may be more convenient during debugging. ### Example: `test_pyuvm` In `test_pyuvm` directory, a `Makefile` and a wrapper `test_pyuvm.py` are placed. ./verification/top/ └── test_pyuvm ├── Makefile ├── test_pyuvm.py ⟵ pytest wrapper └── test_irq └── test_irq.py ⟵ PyUVM test The pytest wrapper can be executed with a command: python -m pytest -sv test_pyuvm.py If you need to run the test directly from the `Makefile`, please look for the decorator in the pytest wrapper to find valid `UVM_TEST` names: @pytest.mark.parametrize("UVM_TEST", ["test_irq.test_irq"]) The test can also be run directly from the Makefile: UVM_TEST=test_irq.test_irq make all Note that HTML report can be produced with flag `--html=index.html` and a markdown report with `--md=test.md` ## CI PyUVM tests are run in CI with the following workflow: .github/workflows/test-verification.yml ================================================ FILE: verification/top/requirements.txt ================================================ # Installing custom cocotb due to: # cocotb scheduler incorrectly handles simulation time # when Verilator is used with flag --timing ${RV_ROOT}/third_party/cocotb # cocotb==1.7.2 cocotb-bus==0.2.1 cocotb-coverage==1.1.0 cocotb-test==0.2.4 pytest==7.4.1 pytest-html==3.2.0 pytest-timeout==2.1.0 pytest-md==0.2.0 pyuvm==2.9.1 ================================================ FILE: verification/top/test_pyuvm/Makefile ================================================ # SPDX-License-Identifier: Apache-2.0 # Copyright 2020 Western Digital Corporation or its affiliates. # Copyright (c) 2023 Antmicro # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # TOPLEVEL_LANG = verilog SIM ?= verilator WAVES ?= 1 NPROC = $$((`nproc`-1)) #Paths CURDIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) CFGDIR := $(abspath $(CURDIR)/snapshots/default) CONFIG := $(RV_ROOT)/configs # ------------------------------------- # VeeR Configuration # ------------------------------------- CONF_PARAMS ?= -set build_axi4 # Check for RV_ROOT ifeq (,$(wildcard ${RV_ROOT}/configs/veer.config)) $(error env var RV_ROOT does not point to a valid dir! Exiting!) endif # ------------------------------------- # Testbench setup # ------------------------------------- MODULE ?= test_irq.test_irq TEST_FILES = $(CURDIR)/test_irq/test_irq.py TOPLEVEL = veer_wrapper SIM_BUILD ?= sim CM_FILE ?= cm.cfg VERILOG_SOURCES = \ $(CFGDIR)/common_defines.vh \ $(RV_ROOT)/design/include/el2_def.sv \ $(CFGDIR)/el2_pdef.vh SIM_FLIST_FILE = $(RV_ROOT)/testbench/flist # ------------------------------------- # Compilation/simulation configuration # ------------------------------------- # Coverage reporting COVERAGE_TYPE?= all ifeq ("$(COVERAGE_TYPE)", "all") VERILATOR_COVERAGE = --coverage else ifeq ("$(COVERAGE_TYPE)", "branch") VERILATOR_COVERAGE = --coverage-line else ifeq ("$(COVERAGE_TYPE)", "toggle") VERILATOR_COVERAGE = --coverage-toggle else ifeq ("$(COVERAGE_TYPE)", "functional") VERILATOR_COVERAGE = --coverage-user else VERILATOR_COVERAGE = "" endif ifeq ($(SIM), verilator) COMPILE_ARGS += --coverage-max-width 20000 COMPILE_ARGS += --timing COMPILE_ARGS += -Wall -Wno-fatal EXTRA_ARGS += --trace --trace-structs EXTRA_ARGS += $(VERILATOR_COVERAGE) EXTRA_ARGS += -I$(CFGDIR) -Wno-DECLFILENAME else ifeq ($(SIM), vcs) EXTRA_ARGS += +incdir+$(CFGDIR) -assert svaext -cm line+cond+fsm+tgl+branch +vcs+lic+wait -cm_libs yv -cm_hier $(CURDIR)/$(CM_FILE) PLUSARGS += +dumpon endif COCOTB_HDL_TIMEUNIT ?= 1ns COCOTB_HDL_TIMEPRECISION ?= 1ps # Build directory ifneq ($(COVERAGE_TYPE),) SIM_BUILD := sim-build-$(COVERAGE_TYPE) endif BUILD_ARGS = -j$(NPROC) # ------------------------------------- # Make PyUVM test with Verilator # ------------------------------------- include $(shell cocotb-config --makefiles)/Makefile.sim $(SIM_BUILD)/Vtop.mk: $(VERILOG_SOURCES) $(CUSTOM_COMPILE_DEPS) $(COCOTB_SHARE_DIR)/lib/verilator/verilator.cpp | $(SIM_BUILD) $(CMD) -cc --exe -Mdir $(SIM_BUILD) -DCOCOTB_SIM=1 $(TOPMODULE_ARG) $(COMPILE_ARGS) $(EXTRA_ARGS) $(VERILOG_SOURCES) -f $(SIM_FLIST_FILE) $(COCOTB_SHARE_DIR)/lib/verilator/verilator.cpp $(SIM_BUILD)/simv: $(VERILOG_SOURCES) $(SIM_BUILD)/pli.tab $(CUSTOM_COMPILE_DEPS) | $(SIM_BUILD) cd $(SIM_BUILD) && \ $(CMD) -top $(TOPLEVEL) $(PLUSARGS) +acc+1 +vpi -P pli.tab +define+COCOTB_SIM=1 -sverilog \ -timescale=$(COCOTB_HDL_TIMEUNIT)/$(COCOTB_HDL_TIMEPRECISION) \ $(EXTRA_ARGS) -debug -load $(shell cocotb-config --lib-name-path vpi vcs) \ $(COMPILE_ARGS) $(VERILOG_SOURCES) -f $(SIM_FLIST_FILE) $(CFGDIR)/common_defines.vh: cd $(CURDIR) && $(CONFIG)/veer.config -fpga_optimize=0 $(CONF_PARAMS) $(EXTRA_CONFIG_OPTS) echo '`undef RV_ASSERT_ON' >> $(CFGDIR)/common_defines.vh ================================================ FILE: verification/top/test_pyuvm/__init__.py ================================================ ================================================ FILE: verification/top/test_pyuvm/cm.cfg ================================================ +tree veer_wrapper.rvtop ////////////////////////////////// MAIN CORE ////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //////////////////////////////// rvrangecheck ///////////////////////////////// // 'start_addr' and 'region' are tied to module parameters -node veer_wrapper.rvtop.veer*rangecheck.start_addr -node veer_wrapper.rvtop.veer*rangecheck.region ////////////////////////////// el2_veer_wrapper /////////////////////////////// -node veer_wrapper.rvtop.unused_dmi_hard_reset -node veer_wrapper.rvtop.trace_rv_i_address_ip[0] /////////////////////////////////// el2_veer ////////////////////////////////// -node veer_wrapper.rvtop.veer.trace_rv_i_address_ip[0] -node veer_wrapper.rvtop.veer.trace_rv_trace_pkt.trace_rv_i_address_ip[0] -node veer_wrapper.rvtop.veer.*hprot[3:1] // Tied to 3'001 /////////////////////////////////// el2_dbg /////////////////////////////////// // Tied to '0 -node veer_wrapper.rvtop.veer.dbg.abstractcs_reg[31:13] -node veer_wrapper.rvtop.veer.dbg.abstractcs_reg[11] -node veer_wrapper.rvtop.veer.dbg.abstractcs_reg[7:4] -node veer_wrapper.rvtop.veer.dbg.dmcontrol_reg[29] -node veer_wrapper.rvtop.veer.dbg.dmcontrol_reg[27:2] -node veer_wrapper.rvtop.veer.dbg.dmstatus_reg[31:20] -node veer_wrapper.rvtop.veer.dbg.dmstatus_reg[15:14] -node veer_wrapper.rvtop.veer.dbg.dmstatus_reg[6:4] -node veer_wrapper.rvtop.veer.dbg.haltsum0_reg[31:1] -node veer_wrapper.rvtop.veer.dbg.sbcs_reg[31:30] -node veer_wrapper.rvtop.veer.dbg.sbcs_reg[28:23] -node veer_wrapper.rvtop.veer.dbg.dmstatus_reg[7] // Tied to '1 -node veer_wrapper.rvtop.veer.dbg.dmstatus_reg[3:0] // Tied to 4'h2 -node veer_wrapper.rvtop.veer.dbg.abstractcs_reg[3:0] // Tied to 4'h2 -node veer_wrapper.rvtop.veer.dbg.sbcs_reg[29] // Tied to '1 -node veer_wrapper.rvtop.veer.dbg.sbcs_reg[11:5] // Tied to 7'h20 -node veer_wrapper.rvtop.veer.dbg.sbcs_reg[4:0] // Tied to 5'b01111 /////////////////////////////////// el2_exu /////////////////////////////////// -node veer_wrapper.rvtop.veer.exu.i_mul.crc32_poly_rev // Tied to 32'hEDB88320 -node veer_wrapper.rvtop.veer.exu.i_mul.crc32c_poly_rev // Tied to 32'h82F63B78 ////////////////////////////////// rvjtag_tap ///////////////////////////////// -node veer_wrapper.rvtop.dmi_wrapper.i_jtag_tap.abits // Tied to AWID[5:0] ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node veer_wrapper.rvtop.veer.dec.tlu.dcsr[14] -node veer_wrapper.rvtop.veer.dec.tlu.dcsr[9] -node veer_wrapper.rvtop.veer.dec.tlu.dcsr[5:4] -node veer_wrapper.rvtop.veer.dec.tlu.dcsr_ns[14] -node veer_wrapper.rvtop.veer.dec.tlu.dcsr_ns[9] -node veer_wrapper.rvtop.veer.dec.tlu.dcsr_ns[5:4] -node veer_wrapper.rvtop.veer.dec.tlu.ifu_mscause[2] -node veer_wrapper.rvtop.veer.dec.tlu.mcgc[6] -node veer_wrapper.rvtop.veer.dec.tlu.mcgc_int[6] -node veer_wrapper.rvtop.veer.dec.tlu.mcgc_ns[6] -node veer_wrapper.rvtop.veer.dec.tlu.mcountinhibit[1] -node veer_wrapper.rvtop.veer.dec.tlu.mepc_rf[0] -node veer_wrapper.rvtop.veer.dec.tlu.mie_rf[31] -node veer_wrapper.rvtop.veer.dec.tlu.mie_rf[27:12] -node veer_wrapper.rvtop.veer.dec.tlu.mie_rf[10:8] -node veer_wrapper.rvtop.veer.dec.tlu.mie_rf[6:4] -node veer_wrapper.rvtop.veer.dec.tlu.mie_rf[2:0] -node veer_wrapper.rvtop.veer.dec.tlu.mip_rf[27:12] -node veer_wrapper.rvtop.veer.dec.tlu.mip_rf[10:8] -node veer_wrapper.rvtop.veer.dec.tlu.mip_rf[6:4] -node veer_wrapper.rvtop.veer.dec.tlu.mip_rf[2:0] -node veer_wrapper.rvtop.veer.dec.tlu.mstatus_rf[31:17] -node veer_wrapper.rvtop.veer.dec.tlu.mstatus_rf[15:12] -node veer_wrapper.rvtop.veer.dec.tlu.mstatus_rf[10:8] -node veer_wrapper.rvtop.veer.dec.tlu.mstatus_rf[6:4] -node veer_wrapper.rvtop.veer.dec.tlu.mstatus_rf[2:0] -node veer_wrapper.rvtop.veer.dec.tlu.mtdata1_tsel_out[26] -node veer_wrapper.rvtop.veer.dec.tlu.mtdata1_tsel_out[18:13] -node veer_wrapper.rvtop.veer.dec.tlu.mtdata1_tsel_out[10:8] -node veer_wrapper.rvtop.veer.dec.tlu.mtdata1_tsel_out[5:3] -node veer_wrapper.rvtop.veer.dec.tlu.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node veer_wrapper.rvtop.veer.dec.tlu.pmp.*pmpcfg_ff.din[6:5] -node veer_wrapper.rvtop.veer.dec.tlu.pmp.*pmpcfg_ff.dout[6:5] -node veer_wrapper.rvtop.veer.dec.tlu.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node veer_wrapper.rvtop.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[30:29] -node veer_wrapper.rvtop.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[22:21] -node veer_wrapper.rvtop.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[14:13] -node veer_wrapper.rvtop.veer.dec.tlu.pmp.pmp_pmpcfg_rddata[6:5] //////////////////////////// el2_ifu_compress_ctl ///////////////////////////// // Tied to '0 -node veer_wrapper.rvtop.veer.ifu.aln.compress0.o[31] -node veer_wrapper.rvtop.veer.ifu.aln.compress0.o[29:21] -node veer_wrapper.rvtop.veer.ifu.aln.compress0.o[19:15] -node veer_wrapper.rvtop.veer.ifu.aln.compress0.o[11:7] -node veer_wrapper.rvtop.veer.ifu.aln.compress0.o[1:0] // Tied to 2'b11 -node veer_wrapper.rvtop.veer.ifu.aln.compress0.l1[1:0] // Tied to o[1:0] (2'b11) -node veer_wrapper.rvtop.veer.ifu.aln.compress0.l2[1:0] // Tied to l1[1:0] (2'b11) -node veer_wrapper.rvtop.veer.ifu.aln.compress0.l3[1:0] // Tied to l2[1:0] (2'b11) -node veer_wrapper.rvtop.veer.ifu.aln.compress0.l1[31] // Tied to o[31] ('0) -node veer_wrapper.rvtop.veer.ifu.aln.compress0.l1[29:25] // Tied to o[29:25] ('0) -node veer_wrapper.rvtop.veer.ifu.aln.compress0.rdpd[4:3] // Tied to 2'01 -node veer_wrapper.rvtop.veer.ifu.aln.compress0.rs2pd[4:3] // Tied to 2'01 ////////////////////////////////// LOCKSTEP /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// //////////////////////////////// rvrangecheck ///////////////////////////////// // 'start_addr' and 'region' are tied to module parameters -node veer_wrapper.rvtop.lockstep.xshadow_core*rangecheck.start_addr -node veer_wrapper.rvtop.lockstep.xshadow_core*rangecheck.region ////////////////////////////// el2_veer_lockstep ////////////////////////////// -node veer_wrapper.rvtop.lockstep.trace_rv_i_address_ip[0] -node veer_wrapper.rvtop.lockstep.*trace_rv_i_address_ip[0] /////////////////////////////////// el2_veer ////////////////////////////////// -node veer_wrapper.rvtop.lockstep.xshadow_core.trace_rv_i_address_ip[0] -node veer_wrapper.rvtop.lockstep.xshadow_core.trace_rv_trace_pkt.trace_rv_i_address_ip[0] -node veer_wrapper.rvtop.lockstep.xshadow_core.*hprot[3:1] // Tied to 3'001 /////////////////////////////////// el2_dbg /////////////////////////////////// // Tied to '0 -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.abstractcs_reg[31:13] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.abstractcs_reg[11] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.abstractcs_reg[7:4] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.dmcontrol_reg[29] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.dmcontrol_reg[27:2] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[31:20] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[15:14] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[6:4] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.haltsum0_reg[31:1] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[31:30] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[28:23] -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[7] // Tied to '1 -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.dmstatus_reg[3:0] // Tied to 4'h2 -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.abstractcs_reg[3:0] // Tied to 4'h2 -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[29] // Tied to '1 -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[11:5] // Tied to 7'h20 -node veer_wrapper.rvtop.lockstep.xshadow_core.dbg.sbcs_reg[4:0] // Tied to 5'b01111 /////////////////////////////////// el2_exu /////////////////////////////////// -node veer_wrapper.rvtop.lockstep.xshadow_core.exu.i_mul.crc32_poly_rev // Tied to 32'hEDB88320 -node veer_wrapper.rvtop.lockstep.xshadow_core.exu.i_mul.crc32c_poly_rev // Tied to 32'h82F63B78 ///////////////////////////////// dec_tlu_ctl ///////////////////////////////// // Tied to '0 -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr[14] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr[9] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr[5:4] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr_ns[14] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr_ns[9] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.dcsr_ns[5:4] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.ifu_mscause[2] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mcgc[6] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mcgc_int[6] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mcgc_ns[6] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mcountinhibit[1] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mepc_rf[0] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[31] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[27:12] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[10:8] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[6:4] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mie_rf[2:0] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mip_rf[27:12] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mip_rf[10:8] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mip_rf[6:4] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mip_rf[2:0] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[31:17] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[15:12] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[10:8] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[6:4] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mstatus_rf[2:0] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[26] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[18:13] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[10:8] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtdata1_tsel_out[5:3] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.mtvec_rf[1] /////////////////////////////// el2_dec_pmp_ctl /////////////////////////////// // Tied to '0 -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.*pmpcfg_ff.din[6:5] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.*pmpcfg_ff.dout[6:5] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.*csr_wdata[6:5] // Aggregation of four 'el2_pmp_cfg_pkt_t' entries // Each 'pmpcfg' entry has 'pmpcfg[6:5]' tied to '0 -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[30:29] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[22:21] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[14:13] -node veer_wrapper.rvtop.lockstep.xshadow_core.dec.tlu.pmp.pmp_pmpcfg_rddata[6:5] //////////////////////////// el2_ifu_compress_ctl ///////////////////////////// // Tied to '0 -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[31] -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[29:21] -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[19:15] -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[11:7] -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.o[1:0] // Tied to 2'b11 -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l1[1:0] // Tied to o[1:0] (2'b11) -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l2[1:0] // Tied to l1[1:0] (2'b11) -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l3[1:0] // Tied to l2[1:0] (2'b11) -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l1[31] // Tied to o[31] ('0) -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.l1[29:25] // Tied to o[29:25] ('0) -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.rdpd[4:3] // Tied to 2'01 -node veer_wrapper.rvtop.lockstep.xshadow_core.ifu.aln.compress0.rs2pd[4:3] // Tied to 2'01 ================================================ FILE: verification/top/test_pyuvm/conftest.py ================================================ import pytest def type_checker_cov(value): msg = "UsageError --coverage=" if value not in ["all", "branch", "toggle", "functional"]: raise pytest.UsageError(msg) return value def type_checker_sim(value): msg = "UsageError --sim=" if value not in ["verilator", "vcs"]: raise pytest.UsageError(msg) return value def pytest_addoption(parser): parser.addoption( "--coverage", action="store", default="toggle", help="--coverage=",type=type_checker_cov ) parser.addoption( "--sim", action="store", default="verilator", help="--sim=",type=type_checker_sim ) parser.addoption( "--conf_params", action="store", default="-set build_axi4", help="--conf_params='...'" ) @pytest.fixture def coverage_opt(request): return request.config.getoption("--coverage") @pytest.fixture def sim_opt(request): return request.config.getoption("--sim") @pytest.fixture def conf_params(request): return request.config.getoption("--conf_params") ================================================ FILE: verification/top/test_pyuvm/test_irq/irq_utils.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: BSD-2-Clause from cocotb.triggers import FallingEdge from cocotb.queue import Queue from pyuvm import * def get_int(signal): try: sig = int(signal.value) except ValueError: sig = 0 return sig class IrqBfm(metaclass=utility_classes.Singleton): """ Interrupt Bus Functional Model Drive: el2_veer_wrapper { input logic nmi_int input logic timer_int input logic soft_int input logic [pt.PIC_TOTAL_INT:1] extintsrc_req } Receive: el2_veer_wrapper { output logic trace_rv_i_interrupt_ip } """ def __init__(self): self.dut = cocotb.top self.interrupt_driver_queue = Queue(maxsize=1) self.interrupt_source_queue = Queue(maxsize=0) self.trace_interrupt_queue = Queue(maxsize=0) self.interrupts = (self.dut.nmi_int, self.dut.soft_int, self.dut.timer_int, self.dut.extintsrc_req) async def send_interrupt_source(self, ints): await self.interrupt_driver_queue.put(ints) async def get_interrupt_source(self): ints = await self.interrupt_source_queue.get() return ints async def get_trace_interrupt(self): ints = await self.trace_interrupt_queue.get() return ints async def reset(self): await FallingEdge(self.dut.clk) self.dut.soft_int.value = 0 self.dut.timer_int.value = 0 self.dut.nmi_int.value = 0 self.dut.extintsrc_req.value = 0 await FallingEdge(self.dut.clk) async def interrupt_driver_bfm(self): self.dut.soft_int.value = 0 self.dut.timer_int.value = 0 self.dut.nmi_int.value = 0 self.dut.extintsrc_req.value = 0 while True: await FallingEdge(self.dut.clk) try: ints = self.interrupt_driver_queue.get_nowait() self.dut.soft_int.value = ints.soft self.dut.timer_int.value = ints.timer self.dut.nmi_int.value = ints.nmi self.dut.extintsrc_req.value = ints.ext except QueueEmpty: pass async def interrupt_source_bfm(self): while True: await FallingEdge(self.dut.clk) item = ( get_int(self.dut.soft_int), get_int(self.dut.timer_int), get_int(self.dut.nmi_int), get_int(self.dut.extintsrc_req) ) self.interrupt_source_queue.put_nowait(item) async def interrupt_trace_bfm(self): while True: await FallingEdge(self.dut.clk) item = get_int(self.dut.trace_rv_i_interrupt_ip) self.trace_interrupt_queue.put_nowait(item) def start_bfm(self): cocotb.start_soon(self.interrupt_driver_bfm()) cocotb.start_soon(self.interrupt_source_bfm()) cocotb.start_soon(self.interrupt_trace_bfm()) ================================================ FILE: verification/top/test_pyuvm/test_irq/irq_uvm.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: BSD-2-Clause import random from pyuvm import * from .irq_utils import IrqBfm class IrqRandomSeq(uvm_sequence): async def body(self): seqr = ConfigDB().get(None, "", "SEQR") random = vIrqSeq("random") await random.start(seqr) class vIrqSeq(uvm_sequence): async def body(self): for i in range(10): int_tr = IrqTriggerSeqItem("irq_trigger", 0, 0, 0, 0) await self.start_item(int_tr) int_tr.randomize() await self.finish_item(int_tr) class IrqTriggerSeqItem(uvm_sequence_item): def __init__(self, name, nmi, soft, timer, ext): super().__init__(name) self.nmi = nmi self.soft = soft self.timer = timer self.ext = ext def __eq__(self, other): same = self.nmi == other.nmi and self.soft == other.soft and self.timer == other.timer and self.ext == other.ext return same def __str__(self): return f"{self.get_name()} : NMI {self.nmi}, SOFT: {self.soft}, TIMER: {self.timer}, EXT: {self.ext:0x}" def randomize(self): self.nmi = random.randrange(2) self.soft = random.randrange(2) self.timer = random.randrange(2) self.ext = random.randrange(2) class IrqMonitor(uvm_monitor): def __init__(self, name, parent, method_name): super().__init__(name, parent) self.method_name = method_name def build_phase(self): self.ap = uvm_analysis_port("ap", self) self.bfm = IrqBfm() self.get_method = getattr(self.bfm, self.method_name) async def run_phase(self): while True: datum = await self.get_method() self.logger.debug(f"MONITORED {datum}") self.ap.write(datum) class Scoreboard(uvm_component): def build_phase(self): self.interrupt_source_fifo = uvm_tlm_analysis_fifo("interrupt_source_fifo",self) self.interrupt_source_get_port = uvm_get_port("interrupt_source_get_port",self) self.interrupt_source_export = self.interrupt_source_fifo.analysis_export self.trace_interrupt_fifo = uvm_tlm_analysis_fifo("trace_interrupt_fifo",self) self.trace_interrupt_get_port = uvm_get_port("trace_interrupt_get_port",self) self.trace_interrupt_export = self.trace_interrupt_fifo.analysis_export def connect_phase(self): self.interrupt_source_get_port.connect(self.interrupt_source_fifo.get_export) self.trace_interrupt_get_port.connect(self.trace_interrupt_fifo.get_export) def check_phase(self): passed = True try: self.errors = ConfigDB().get(self, "", "CREATE_ERRORS") except UVMConfigItemNotFound: self.errors = False assert passed class IrqDriver(uvm_driver): def build_phase(self): self.ap = uvm_analysis_port("ap", self) def start_of_simulation_phase(self): self.bfm = IrqBfm() async def initialize_tb(self): await self.bfm.reset() self.bfm.start_bfm() async def run_phase(self): await self.initialize_tb() while True: ints = await self.seq_item_port.get_next_item() await self.bfm.send_interrupt_source(ints) result = await self.bfm.get_trace_interrupt() self.ap.write(result) self.seq_item_port.item_done() class IrqAgent(uvm_agent): def build_phase(self): self.seqr = uvm_sequencer("seqr", self) ConfigDB().set(None, "*", "SEQR", self.seqr) self.monitor = IrqMonitor("int_monitor", self, "get_interrupt_source") self.driver = IrqDriver("int_driver", self) def connect_phase(self): # Driver takes sequence items from sequencer self.driver.seq_item_port.connect(self.seqr.seq_item_export) class VeerEl2Env(uvm_env): def build_phase(self): self.scoreboard = Scoreboard("scoreboard", self) self.agent = IrqAgent("agent",self) def connect_phase(self): # Monitor pushes observed data to the scoreboard self.agent.monitor.ap.connect(self.scoreboard.interrupt_source_export) # Driver self.agent.driver.ap.connect(self.scoreboard.trace_interrupt_export) ================================================ FILE: verification/top/test_pyuvm/test_irq/test_irq.py ================================================ # # Copyright (c) 2023 Antmicro # SPDX-License-Identifier: BSD-2-Clause import pyuvm from pyuvm import * from .irq_uvm import VeerEl2Env, IrqRandomSeq from cocotb.clock import Clock @pyuvm.test() class BaseTest(uvm_test): def build_phase(self): self.set_default_logging_level(logging.DEBUG) self.env = VeerEl2Env("env", self) def end_of_elaboration_phase(self): self.test_all = IrqRandomSeq.create("test_irq") async def run_phase(self): self.raise_objection() clock = Clock(cocotb.top.clk, 10, units="ns") cocotb.start_soon(clock.start(start_high=False)) await self.test_all.start() self.drop_objection() ================================================ FILE: verification/top/test_pyuvm/test_pyuvm.py ================================================ import pytest import os import subprocess class TestPyUVM(): @pytest.mark.parametrize("UVM_TEST", ["test_irq.test_irq"]) def test_pyuvm(self, UVM_TEST, coverage_opt, sim_opt, conf_params): os.environ["UVM_TEST"] = UVM_TEST py_command = [] py_command += [f"COVERAGE_TYPE={coverage_opt}"] py_command += [f"SIM={sim_opt}"] py_command += [f"CONF_PARAMS='{conf_params}'"] py_command += [ "make clean all", ] py_command = " ".join(py_command) print(f"\n----- PyTest -----") print(f":: py_command >> {py_command}") p = subprocess.run(py_command, shell=True, executable="/bin/bash", bufsize=0) print(f"\n------------------") print(f"----- Subprocess Summary -----") print(f"p.check_returncode") p.check_returncode() print(f"------------------------------") ================================================ FILE: violations.waiver ================================================ waive --rule=module-filename --location="design/lib/.*_lib.sv" waive --rule=line-length --location="design/ifu/.*.sv" waive --rule=line-length --location="design/dec/.*.sv" waive --rule=line-length --location="design/lsu/.*.sv" waive --rule=line-length --location="design/el2_.*_ctrl.sv" waive --rule=no-trailing-spaces --location="design/ifu/.*.sv" waive --rule=no-trailing-spaces --location="design/el2_.*_ctrl.sv" waive --rule=generate-label --location="design/lsu/el2_.*.sv" waive --rule=explicit-parameter-storage-type --location="design/el2_pmp.sv" waive --rule=explicit-parameter-storage-type --location="design/dec/el2_dec_pmp_ctl.sv"