Created
May 4, 2026 08:07
-
-
Save mlyoung101/1756c6f4361b8e87316d235354b03eff to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Dump of all post-preprocessor input | |
| // Blank lines and `line directives have been removed | |
| // | |
| // Information: | |
| // Version: Verilator 5.048 2026-04-26 rev v5.048 | |
| // Arguments: --lint-only --top-module tb_axi_xbar --timing -j 10 +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/clk_rst_gen.sv /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/sim_timeout.sv /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/stream_watchdog.sv /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/signal_highlighter.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/rand_id_queue.sv /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/rand_stream_mst.sv /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/rand_synch_holdable_driver.sv /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/rand_verif_pkg.sv /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/rand_synch_driver.sv /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/src/rand_stream_slv.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR /home/mel/build/axi/.bender/git/checkouts/common_verification-5b9bacfe2f79eb87/test/tb_clk_rst_gen.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR /home/mel/build/axi/.bender/git/checkouts/tech_cells_generic-6e6736c6cf5dbb6b/src/rtl/tc_sram.sv /home/mel/build/axi/.bender/git/checkouts/tech_cells_generic-6e6736c6cf5dbb6b/src/rtl/tc_sram_impl.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR /home/mel/build/axi/.bender/git/checkouts/tech_cells_generic-6e6736c6cf5dbb6b/src/rtl/tc_clk.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR /home/mel/build/axi/.bender/git/checkouts/tech_cells_generic-6e6736c6cf5dbb6b/test/tb_tc_sram.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR /home/mel/build/axi/.bender/git/checkouts/tech_cells_generic-6e6736c6cf5dbb6b/src/deprecated/pulp_clock_gating_async.sv /home/mel/build/axi/.bender/git/checkouts/tech_cells_generic-6e6736c6cf5dbb6b/src/deprecated/cluster_clk_cells.sv /home/mel/build/axi/.bender/git/checkouts/tech_cells_generic-6e6736c6cf5dbb6b/src/deprecated/pulp_clk_cells.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR +incdir+/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/include /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/binary_to_gray.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR +incdir+/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/include /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cb_filter_pkg.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cc_onehot.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_reset_ctrlr_pkg.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cf_math_pkg.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/clk_int_div.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/credit_counter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/delta_counter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ecc_pkg.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/edge_propagator_tx.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/exp_backoff.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/fifo_v3.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/gray_to_binary.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/heaviside.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/isochronous_4phase_handshake.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/isochronous_spill_register.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr_16bit.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr_8bit.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lossy_valid_to_stream.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/mv_filter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/onehot_to_bin.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/plru_tree.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/passthrough_stream_fifo.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/popcount.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ring_buffer.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rstgen_bypass.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/serial_deglitch.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/shift_reg.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/shift_reg_gated.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/spill_register_flushable.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_demux.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_filter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_fork.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_intf.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_join_dynamic.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_mux.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_throttle.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/sub_per_hash.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/sync.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/sync_wedge.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/unread.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/read.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/addr_decode_dync.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/boxcar.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_2phase.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_4phase.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/clk_int_div_static.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/trip_counter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/addr_decode.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/addr_decode_napot.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/multiaddr_decode.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR +incdir+/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/include /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cb_filter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_fifo_2phase.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/clk_mux_glitch_free.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/counter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ecc_decode.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ecc_encode.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/edge_detect.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lzc.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/max_counter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rstgen.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/spill_register.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_delay.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_fifo.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_fork_dynamic.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_join.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_reset_ctrlr.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_fifo_gray.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/fall_through_register.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/id_queue.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_to_mem.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_arbiter_flushable.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_fifo_optimal_wrap.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_register.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_fifo_gray_clearable.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_2phase_clearable.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/mem_to_banks_detailed.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_arbiter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/mem_to_banks.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR +incdir+/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/include /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/addr_decode_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/cb_filter_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/cdc_2phase_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/cdc_2phase_clearable_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/cdc_fifo_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/cdc_fifo_clearable_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/fifo_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/graycode_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/id_queue_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/passthrough_stream_fifo_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/popcount_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/rr_arb_tree_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/stream_test.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/stream_register_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/stream_to_mem_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/sub_per_hash_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/isochronous_crossing_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/stream_omega_net_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/stream_xbar_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/clk_int_div_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/clk_int_div_static_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/clk_mux_glitch_free_tb.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/lossy_valid_to_stream_tb.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR +incdir+/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/include /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/clock_divider_counter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/clk_div.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/find_first_one.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/generic_LFSR_8bit.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/generic_fifo.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/prioarbiter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/pulp_sync.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/pulp_sync_wedge.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/rrarbiter.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/clock_divider.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/fifo_v2.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/deprecated/fifo_v1.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/edge_propagator_ack.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/edge_propagator.sv /home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/edge_propagator_rx.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR +incdir+/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/include +incdir+/home/mel/build/axi/include /home/mel/build/axi/src/axi_pkg.sv /home/mel/build/axi/src/axi_demux_id_counters.sv /home/mel/build/axi/src/axi_intf.sv /home/mel/build/axi/src/axi_atop_filter.sv /home/mel/build/axi/src/axi_burst_splitter_gran.sv /home/mel/build/axi/src/axi_burst_unwrap.sv /home/mel/build/axi/src/axi_bus_compare.sv /home/mel/build/axi/src/axi_cdc_dst.sv /home/mel/build/axi/src/axi_cdc_src.sv /home/mel/build/axi/src/axi_cut.sv /home/mel/build/axi/src/axi_delayer.sv /home/mel/build/axi/src/axi_demux_simple.sv /home/mel/build/axi/src/axi_dw_downsizer.sv /home/mel/build/axi/src/axi_dw_upsizer.sv /home/mel/build/axi/src/axi_fifo.sv /home/mel/build/axi/src/axi_fifo_delay_dyn.sv /home/mel/build/axi/src/axi_id_remap.sv /home/mel/build/axi/src/axi_id_prepend.sv /home/mel/build/axi/src/axi_inval_filter.sv /home/mel/build/axi/src/axi_isolate.sv /home/mel/build/axi/src/axi_join.sv /home/mel/build/axi/src/axi_lite_demux.sv /home/mel/build/axi/src/axi_lite_dw_converter.sv /home/mel/build/axi/src/axi_lite_from_mem.sv /home/mel/build/axi/src/axi_lite_join.sv /home/mel/build/axi/src/axi_lite_lfsr.sv /home/mel/build/axi/src/axi_lite_mailbox.sv /home/mel/build/axi/src/axi_lite_mux.sv /home/mel/build/axi/src/axi_lite_regs.sv /home/mel/build/axi/src/axi_lite_to_apb.sv /home/mel/build/axi/src/axi_lite_to_axi.sv /home/mel/build/axi/src/axi_modify_address.sv /home/mel/build/axi/src/axi_mux.sv /home/mel/build/axi/src/axi_rw_join.sv /home/mel/build/axi/src/axi_rw_split.sv /home/mel/build/axi/src/axi_serializer.sv /home/mel/build/axi/src/axi_slave_compare.sv /home/mel/build/axi/src/axi_throttle.sv /home/mel/build/axi/src/axi_to_detailed_mem.sv /home/mel/build/axi/src/axi_burst_splitter.sv /home/mel/build/axi/src/axi_cdc.sv /home/mel/build/axi/src/axi_demux.sv /home/mel/build/axi/src/axi_err_slv.sv /home/mel/build/axi/src/axi_dw_converter.sv /home/mel/build/axi/src/axi_from_mem.sv /home/mel/build/axi/src/axi_id_serialize.sv /home/mel/build/axi/src/axi_lfsr.sv /home/mel/build/axi/src/axi_multicut.sv /home/mel/build/axi/src/axi_to_axi_lite.sv /home/mel/build/axi/src/axi_to_mem.sv /home/mel/build/axi/src/axi_zero_mem.sv /home/mel/build/axi/src/axi_interleaved_xbar.sv /home/mel/build/axi/src/axi_iw_converter.sv /home/mel/build/axi/src/axi_lite_xbar.sv /home/mel/build/axi/src/axi_xbar_unmuxed.sv /home/mel/build/axi/src/axi_to_mem_banked.sv /home/mel/build/axi/src/axi_to_mem_interleaved.sv /home/mel/build/axi/src/axi_to_mem_split.sv /home/mel/build/axi/src/axi_xbar.sv /home/mel/build/axi/src/axi_xp.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR +incdir+/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/include +incdir+/home/mel/build/axi/include /home/mel/build/axi/src/axi_chan_compare.sv /home/mel/build/axi/src/axi_dumper.sv /home/mel/build/axi/src/axi_sim_mem.sv /home/mel/build/axi/src/axi_test.sv +define+TARGET_SIMULATION +define+TARGET_SYNTHESIS +define+TARGET_TEST +define+TARGET_VERILATOR +incdir+/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/include +incdir+/home/mel/build/axi/include /home/mel/build/axi/test/tb_axi_dw_pkg.sv /home/mel/build/axi/test/tb_axi_xbar_pkg.sv /home/mel/build/axi/test/tb_axi_addr_test.sv /home/mel/build/axi/test/tb_axi_atop_filter.sv /home/mel/build/axi/test/tb_axi_bus_compare.sv /home/mel/build/axi/test/tb_axi_cdc.sv /home/mel/build/axi/test/tb_axi_delayer.sv /home/mel/build/axi/test/tb_axi_dw_downsizer.sv /home/mel/build/axi/test/tb_axi_dw_upsizer.sv /home/mel/build/axi/test/tb_axi_fifo.sv /home/mel/build/axi/test/tb_axi_isolate.sv /home/mel/build/axi/test/tb_axi_lite_dw_converter.sv /home/mel/build/axi/test/tb_axi_lite_mailbox.sv /home/mel/build/axi/test/tb_axi_lite_regs.sv /home/mel/build/axi/test/tb_axi_iw_converter.sv /home/mel/build/axi/test/tb_axi_lite_to_apb.sv /home/mel/build/axi/test/tb_axi_lite_to_axi.sv /home/mel/build/axi/test/tb_axi_lite_xbar.sv /home/mel/build/axi/test/tb_axi_modify_address.sv /home/mel/build/axi/test/tb_axi_serializer.sv /home/mel/build/axi/test/tb_axi_sim_mem.sv /home/mel/build/axi/test/tb_axi_slave_compare.sv /home/mel/build/axi/test/tb_axi_to_axi_lite.sv /home/mel/build/axi/test/tb_axi_to_mem_banked.sv /home/mel/build/axi/test/tb_axi_xbar.sv --debug | |
| // Build jobs: 10 | |
| // Verilate jobs: 10 | |
| // verilator fargs --lint-only | |
| // verilator fargs --top-module tb_axi_xbar | |
| // verilator fargs --timing | |
| // verilator fargs -j 10 | |
| `begin_keywords "1800-2023" | |
| module clk_rst_gen #( | |
| parameter time ClkPeriod = 0ps, | |
| parameter int unsigned RstClkCycles = 0 | |
| ) ( | |
| output logic clk_o, | |
| output logic rst_no | |
| ); | |
| logic clk; | |
| initial begin | |
| clk = 1'b0; | |
| end | |
| always begin | |
| clk = 1'b1; | |
| #(ClkPeriod / 2); | |
| clk = 1'b0; | |
| #((ClkPeriod + 1) / 2); | |
| end | |
| assign clk_o = clk; | |
| initial begin | |
| static int unsigned rst_cnt = 0; | |
| rst_no = 1'b0; | |
| #(ClkPeriod / 2); | |
| while (rst_cnt < RstClkCycles) begin | |
| @(posedge clk); | |
| rst_cnt++; | |
| end | |
| rst_no = 1'b1; | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module sim_timeout #( | |
| parameter longint unsigned Cycles = 0, | |
| parameter bit ResetRestartsTimeout = 1'b0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni | |
| ); | |
| longint unsigned cycles = 0; | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (ResetRestartsTimeout && !rst_ni) begin | |
| cycles <= 0; | |
| end else begin | |
| cycles <= cycles + 1; | |
| end | |
| if (cycles > Cycles) begin | |
| $fatal(1, "Timeout exceeded!"); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_watchdog #( | |
| parameter int unsigned NumCycles | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic valid_i, | |
| input logic ready_i | |
| ); | |
| int unsigned cnt; | |
| initial begin : wd | |
| cnt = NumCycles; | |
| while (cnt > 0) begin | |
| if (valid_i && ready_i || !rst_ni) begin | |
| cnt = NumCycles; | |
| end else begin | |
| cnt--; | |
| end | |
| @(posedge clk_i); | |
| end | |
| $fatal(1, "Tripped Watchdog (%m) at %dns, Inactivity for %d cycles", $time(), NumCycles); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module signal_highlighter #( | |
| parameter type T = logic | |
| )( | |
| input logic ready_i, | |
| input logic valid_i, | |
| input T data_i | |
| ); | |
| T in_wave; | |
| always_comb begin | |
| in_wave = 'Z; | |
| if (ready_i & valid_i) begin | |
| in_wave = data_i; | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| package rand_id_queue_pkg; | |
| class rand_id_queue #( | |
| type data_t = logic, | |
| int unsigned ID_WIDTH = 0 | |
| ); | |
| localparam int unsigned N_IDS = 2**ID_WIDTH; | |
| localparam type id_t = logic[ID_WIDTH-1:0]; | |
| data_t queues[N_IDS-1:0][$]; | |
| int unsigned size; | |
| function new(); | |
| size = 0; | |
| endfunction | |
| function void push(id_t id, data_t data); | |
| queues[id].push_back(data); | |
| size++; | |
| endfunction | |
| function bit empty(); | |
| return (size == 0); | |
| endfunction | |
| function bit is_empty(); | |
| return (size == 0); | |
| endfunction | |
| function data_t peek(); | |
| return queues[rand_id()][0]; | |
| endfunction | |
| function data_t pop(); | |
| return pop_id(rand_id()); | |
| endfunction | |
| function data_t pop_id(id_t id); | |
| size--; | |
| return queues[id].pop_front(); | |
| endfunction | |
| function id_t rand_id(); | |
| if (!is_empty()) begin | |
| id_t id; | |
| do begin | |
| void'(std::randomize(id)); | |
| end while (queues[id].size() == 0); | |
| return id; | |
| end else begin | |
| return 'x; | |
| end | |
| endfunction | |
| function void set(id_t id, data_t data); | |
| queues[id][0] = data; | |
| endfunction | |
| function data_t get(id_t id); | |
| return queues[id][0]; | |
| endfunction | |
| endclass | |
| endpackage | |
| `begin_keywords "1800-2023" | |
| module rand_stream_mst #( | |
| parameter type data_t = logic, | |
| parameter int MinWaitCycles = -1, | |
| parameter int MaxWaitCycles = -1, | |
| parameter time ApplDelay = 0ps, | |
| parameter time AcqDelay = 0ps | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| output data_t data_o, | |
| output logic valid_o, | |
| input logic ready_i | |
| ); | |
| int unsigned rand_wait_cycles; | |
| function static void randomize_wait_cycles(); | |
| int unsigned rand_success; | |
| rand_success = std::randomize(rand_wait_cycles) with { | |
| rand_wait_cycles >= MinWaitCycles; | |
| rand_wait_cycles <= MaxWaitCycles; | |
| }; | |
| assert (rand_success) else $error("Failed to randomize wait cycles!"); | |
| endfunction | |
| initial begin | |
| data_o = '0; | |
| valid_o = 1'b0; | |
| wait (rst_ni); | |
| randomize_wait_cycles(); | |
| @(posedge clk_i); | |
| forever begin | |
| repeat(rand_wait_cycles) begin | |
| @(posedge clk_i); | |
| end | |
| #(ApplDelay); | |
| void'(std::randomize(data_o)); | |
| valid_o = 1'b1; | |
| #(AcqDelay-ApplDelay); | |
| while (!ready_i) begin | |
| @(posedge clk_i); | |
| #(AcqDelay); | |
| end | |
| randomize_wait_cycles(); | |
| if (rand_wait_cycles == 0) begin | |
| @(posedge clk_i); | |
| end else begin | |
| @(posedge clk_i); | |
| #(ApplDelay); | |
| valid_o = 1'b0; | |
| void'(std::randomize(data_o)); | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module rand_synch_holdable_driver #( | |
| parameter type data_t = logic, | |
| parameter int MinWaitCycles = -1, | |
| parameter int MaxWaitCycles = -1, | |
| parameter time ApplDelay = 0ps | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic hold_i, | |
| output data_t data_o | |
| ); | |
| initial begin | |
| int unsigned rand_delay, rand_success; | |
| data_o = '0; | |
| wait (rst_ni); | |
| @(posedge clk_i); | |
| forever begin | |
| rand_success = std::randomize(rand_delay) with { | |
| rand_delay >= MinWaitCycles; | |
| rand_delay <= MaxWaitCycles; | |
| }; | |
| assert (rand_success) else $error("Failed to randomize wait cycles!"); | |
| repeat(rand_delay) begin | |
| @(posedge clk_i); | |
| end | |
| #(ApplDelay); | |
| if (!hold_i) begin | |
| void'(std::randomize(data_o)); | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| package rand_verif_pkg; | |
| task automatic rand_wait(input int unsigned min, max, ref logic clk); | |
| int unsigned rand_success, cycles; | |
| rand_success = std::randomize(cycles) with { | |
| cycles >= min; | |
| cycles <= max; | |
| }; | |
| assert (rand_success) else $error("Failed to randomize wait cycles!"); | |
| repeat (cycles) @(posedge clk); | |
| endtask | |
| endpackage | |
| `begin_keywords "1800-2023" | |
| module rand_synch_driver #( | |
| parameter type data_t = logic, | |
| parameter int MinWaitCycles = -1, | |
| parameter int MaxWaitCycles = -1, | |
| parameter time ApplDelay = 0ps | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| output data_t data_o | |
| ); | |
| rand_synch_holdable_driver #( | |
| .data_t (data_t), | |
| .MinWaitCycles (MinWaitCycles), | |
| .MaxWaitCycles (MaxWaitCycles), | |
| .ApplDelay (ApplDelay) | |
| ) i_ready_driver ( | |
| .clk_i (clk_i), | |
| .rst_ni (rst_ni), | |
| .hold_i (1'b0), | |
| .data_o (data_o) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module rand_stream_slv #( | |
| parameter type data_t = logic, | |
| parameter int MinWaitCycles = -1, | |
| parameter int MaxWaitCycles = -1, | |
| parameter time ApplDelay = 0ps, | |
| parameter time AcqDelay = 0ps, | |
| parameter bit Enqueue = 1'b0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input data_t data_i, | |
| input logic valid_i, | |
| output logic ready_o | |
| ); | |
| if (Enqueue) begin: gen_queue | |
| data_t queue[$]; | |
| always @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| queue = {}; | |
| end else begin | |
| #(AcqDelay); | |
| if (valid_i && ready_o) begin | |
| queue.push_back(data_i); | |
| end | |
| end | |
| end | |
| end | |
| rand_synch_driver #( | |
| .data_t (logic), | |
| .MinWaitCycles (MinWaitCycles), | |
| .MaxWaitCycles (MaxWaitCycles), | |
| .ApplDelay (ApplDelay) | |
| ) i_ready_driver ( | |
| .clk_i (clk_i), | |
| .rst_ni (rst_ni), | |
| .data_o (ready_o) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module tb_clk_rst_gen #( | |
| parameter time TbClkPeriod = 10ns, | |
| parameter int unsigned TbClkCycles = 12, | |
| parameter int unsigned TbRstClkCycles = 7, | |
| parameter bit TbDebugPrint = 1'b0 | |
| ) (); | |
| logic clk, | |
| rst_n; | |
| clk_rst_gen #( | |
| .ClkPeriod (TbClkPeriod), | |
| .RstClkCycles (TbRstClkCycles) | |
| ) i_dut ( | |
| .clk_o (clk), | |
| .rst_no (rst_n) | |
| ); | |
| int unsigned clk_cnt, | |
| rst_cnt; | |
| initial begin | |
| clk_cnt = 0; | |
| rst_cnt = 0; | |
| while (1) begin | |
| #(TbClkPeriod - 1); | |
| if (rst_n == 1'b0) begin | |
| rst_cnt++; | |
| if (TbDebugPrint) $info("Reset clock cycle complete"); | |
| end | |
| @(posedge clk); | |
| clk_cnt++; | |
| if (TbDebugPrint) $info("Clock cycle complete"); | |
| end | |
| end | |
| initial begin | |
| static time TB_RUN_TIME = TbClkCycles * TbClkPeriod + (TbClkPeriod / 2); | |
| assert (TbRstClkCycles < TbClkCycles) | |
| else $fatal(1, "The number of clock cycles must be larger than the number of reset cycles!"); | |
| #TB_RUN_TIME; | |
| assert (clk_cnt == TbClkCycles) | |
| else $error("Counted %0d instead of %0d clock cycles!", clk_cnt, TbClkCycles); | |
| assert (rst_cnt == TbRstClkCycles) | |
| else $error("Counted %0d instead of %0d reset clock cycles!", rst_cnt, TbRstClkCycles); | |
| $finish(); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module tc_sram #( | |
| parameter int unsigned NumWords = 32'd1024, | |
| parameter int unsigned DataWidth = 32'd128, | |
| parameter int unsigned ByteWidth = 32'd8, | |
| parameter int unsigned NumPorts = 32'd2, | |
| parameter int unsigned Latency = 32'd1, | |
| parameter SimInit = "none", | |
| parameter bit PrintSimCfg = 1'b0, | |
| parameter ImplKey = "none", | |
| parameter int unsigned AddrWidth = (NumWords > 32'd1) ? $clog2(NumWords) : 32'd1, | |
| parameter int unsigned BeWidth = (DataWidth + ByteWidth - 32'd1) / ByteWidth, | |
| parameter type addr_t = logic [AddrWidth-1:0], | |
| parameter type data_t = logic [DataWidth-1:0], | |
| parameter type be_t = logic [BeWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic [NumPorts-1:0] req_i, | |
| input logic [NumPorts-1:0] we_i, | |
| input addr_t [NumPorts-1:0] addr_i, | |
| input data_t [NumPorts-1:0] wdata_i, | |
| input be_t [NumPorts-1:0] be_i, | |
| output data_t [NumPorts-1:0] rdata_o | |
| ); | |
| data_t sram [NumWords-1:0]; | |
| addr_t [NumPorts-1:0] r_addr_q; | |
| data_t init_val[NumWords-1:0]; | |
| initial begin : proc_sram_init | |
| for (int unsigned i = 0; i < NumWords; i++) begin | |
| case (SimInit) | |
| "zeros": init_val[i] = {DataWidth{1'b0}}; | |
| "ones": init_val[i] = {DataWidth{1'b1}}; | |
| "random": init_val[i] = {DataWidth{$urandom()}}; | |
| default: init_val[i] = {DataWidth{1'bx}}; | |
| endcase | |
| end | |
| end | |
| data_t [NumPorts-1:0][Latency-1:0] rdata_q, rdata_d; | |
| if (Latency == 32'd0) begin : gen_no_read_lat | |
| for (genvar i = 0; i < NumPorts; i++) begin : gen_port | |
| assign rdata_o[i] = (req_i[i] && !we_i[i]) ? sram[addr_i[i]] : sram[r_addr_q[i]]; | |
| end | |
| end else begin : gen_read_lat | |
| always_comb begin | |
| for (int unsigned i = 0; i < NumPorts; i++) begin | |
| rdata_o[i] = rdata_q[i][0]; | |
| for (int unsigned j = 0; j < (Latency-1); j++) begin | |
| rdata_d[i][j] = rdata_q[i][j+1]; | |
| end | |
| rdata_d[i][Latency-1] = (req_i[i] && !we_i[i]) ? sram[addr_i[i]] : sram[r_addr_q[i]]; | |
| end | |
| end | |
| end | |
| if (SimInit == "none") begin | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| for (int i = 0; i < NumPorts; i++) begin | |
| r_addr_q[i] <= {AddrWidth{1'b0}}; | |
| end | |
| end else begin | |
| for (int unsigned i = 0; i < NumPorts; i++) begin | |
| if (Latency != 0) begin | |
| for (int unsigned j = 0; j < Latency; j++) begin | |
| rdata_q[i][j] <= rdata_d[i][j]; | |
| end | |
| end | |
| end | |
| for (int unsigned i = 0; i < NumPorts; i++) begin | |
| if (req_i[i]) begin | |
| if (we_i[i]) begin | |
| for (int unsigned j = 0; j < BeWidth; j++) begin | |
| if (be_i[i][j]) begin | |
| sram[addr_i[i]][j*ByteWidth+:ByteWidth] <= wdata_i[i][j*ByteWidth+:ByteWidth]; | |
| end | |
| end | |
| end else begin | |
| r_addr_q[i] <= addr_i[i]; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| end else begin | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| sram <= init_val; | |
| for (int i = 0; i < NumPorts; i++) begin | |
| r_addr_q[i] <= {AddrWidth{1'b0}}; | |
| if (Latency != 32'd0) begin | |
| for (int unsigned j = 0; j < Latency; j++) begin | |
| rdata_q[i][j] <= init_val[{AddrWidth{1'b0}}]; | |
| end | |
| end | |
| end | |
| end else begin | |
| for (int unsigned i = 0; i < NumPorts; i++) begin | |
| if (Latency != 0) begin | |
| for (int unsigned j = 0; j < Latency; j++) begin | |
| rdata_q[i][j] <= rdata_d[i][j]; | |
| end | |
| end | |
| end | |
| for (int unsigned i = 0; i < NumPorts; i++) begin | |
| if (req_i[i]) begin | |
| if (we_i[i]) begin | |
| for (int unsigned j = 0; j < BeWidth; j++) begin | |
| if (be_i[i][j]) begin | |
| sram[addr_i[i]][j*ByteWidth+:ByteWidth] <= wdata_i[i][j*ByteWidth+:ByteWidth]; | |
| end | |
| end | |
| end else begin | |
| r_addr_q[i] <= addr_i[i]; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module tc_sram_impl #( | |
| parameter int unsigned NumWords = 32'd1024, | |
| parameter int unsigned DataWidth = 32'd128, | |
| parameter int unsigned ByteWidth = 32'd8, | |
| parameter int unsigned NumPorts = 32'd2, | |
| parameter int unsigned Latency = 32'd1, | |
| parameter SimInit = "none", | |
| parameter bit PrintSimCfg = 1'b0, | |
| parameter ImplKey = "none", | |
| parameter type impl_in_t = logic, | |
| parameter type impl_out_t = logic, | |
| parameter impl_out_t ImplOutSim = 'X, | |
| parameter int unsigned AddrWidth = (NumWords > 32'd1) ? $clog2(NumWords) : 32'd1, | |
| parameter int unsigned BeWidth = (DataWidth + ByteWidth - 32'd1) / ByteWidth, | |
| parameter type addr_t = logic [AddrWidth-1:0], | |
| parameter type data_t = logic [DataWidth-1:0], | |
| parameter type be_t = logic [BeWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input impl_in_t impl_i, | |
| output impl_out_t impl_o, | |
| input logic [NumPorts-1:0] req_i, | |
| input logic [NumPorts-1:0] we_i, | |
| input addr_t [NumPorts-1:0] addr_i, | |
| input data_t [NumPorts-1:0] wdata_i, | |
| input be_t [NumPorts-1:0] be_i, | |
| output data_t [NumPorts-1:0] rdata_o | |
| ); | |
| assign impl_o = ImplOutSim; | |
| tc_sram #( | |
| .NumWords ( NumWords ), | |
| .DataWidth ( DataWidth ), | |
| .ByteWidth ( ByteWidth ), | |
| .NumPorts ( NumPorts ), | |
| .Latency ( Latency ), | |
| .SimInit ( SimInit ), | |
| .PrintSimCfg ( PrintSimCfg ), | |
| .ImplKey ( ImplKey ) | |
| ) i_tc_sram ( | |
| .clk_i, | |
| .rst_ni, | |
| .req_i, | |
| .we_i, | |
| .addr_i, | |
| .wdata_i, | |
| .be_i, | |
| .rdata_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module tc_clk_and2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| output logic clk_o | |
| ); | |
| assign clk_o = clk0_i & clk1_i; | |
| endmodule | |
| module tc_clk_buffer ( | |
| input logic clk_i, | |
| output logic clk_o | |
| ); | |
| assign clk_o = clk_i; | |
| endmodule | |
| module tc_clk_gating #( | |
| parameter bit IS_FUNCTIONAL = 1'b1 | |
| )( | |
| input logic clk_i, | |
| input logic en_i, | |
| input logic test_en_i, | |
| output logic clk_o | |
| ); | |
| logic clk_en; | |
| always_latch begin | |
| if (clk_i == 1'b0) clk_en <= en_i | test_en_i; | |
| end | |
| assign clk_o = clk_i & clk_en; | |
| endmodule | |
| module tc_clk_inverter ( | |
| input logic clk_i, | |
| output logic clk_o | |
| ); | |
| assign clk_o = ~clk_i; | |
| endmodule | |
| module tc_clk_mux2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| input logic clk_sel_i, | |
| output logic clk_o | |
| ); | |
| assign clk_o = (clk_sel_i) ? clk1_i : clk0_i; | |
| endmodule | |
| module tc_clk_xor2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| output logic clk_o | |
| ); | |
| assign clk_o = clk0_i ^ clk1_i; | |
| endmodule | |
| module tc_clk_or2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| output logic clk_o | |
| ); | |
| assign clk_o = clk0_i | clk1_i; | |
| endmodule | |
| module tc_clk_delay #( | |
| parameter int unsigned Delay = 300ps | |
| ) ( | |
| input logic in_i, | |
| output logic out_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module tb_tc_sram #( | |
| parameter int unsigned NumPorts = 32'd2, | |
| parameter int unsigned Latency = 32'd1, | |
| parameter int unsigned NumWords = 32'd1024, | |
| parameter int unsigned DataWidth = 32'd64, | |
| parameter int unsigned ByteWidth = 32'd8, | |
| parameter int unsigned NoReq = 32'd200000, | |
| parameter string SimInit = "zeros", | |
| parameter time CyclTime = 10ns, | |
| parameter time ApplTime = 2ns, | |
| parameter time TestTime = 8ns | |
| ); | |
| logic clk, rst_n; | |
| clk_rst_gen #( | |
| .ClkPeriod ( CyclTime ), | |
| .RstClkCycles( 5 ) | |
| ) i_clk_gen ( | |
| .clk_o ( clk ), | |
| .rst_no ( rst_n ) | |
| ); | |
| logic [NumPorts-1:0] done; | |
| localparam int unsigned AddrWidth = (NumWords > 32'd1) ? $clog2(NumWords) : 32'd1; | |
| localparam int unsigned BeWidth = (DataWidth + ByteWidth - 32'd1) / ByteWidth; | |
| typedef logic [AddrWidth-1:0] addr_t; | |
| typedef logic [DataWidth-1:0] data_t; | |
| typedef logic [BeWidth-1:0] be_t; | |
| logic [NumPorts-1:0] req, we; | |
| addr_t [NumPorts-1:0] addr; | |
| data_t [NumPorts-1:0] wdata, rdata; | |
| be_t [NumPorts-1:0] be; | |
| data_t memory [NumWords-1:0]; | |
| longint unsigned failed_test; | |
| for (genvar i = 0; i < NumPorts; i++) begin : gen_stimuli | |
| initial begin : proc_drive_port | |
| automatic logic stim_write; | |
| automatic addr_t stim_addr; | |
| automatic data_t stim_data; | |
| automatic be_t stim_be; | |
| done[i] <= 1'b0; | |
| req[i] <= 1'b0; | |
| we[i] <= 1'b0; | |
| addr[i] <= addr_t'(0); | |
| wdata[i] <= data_t'(0); | |
| be[i] <= be_t'(0); | |
| @(posedge rst_n); | |
| repeat (10) @(posedge clk); | |
| for (int unsigned j = 0; j < NoReq; j++) begin | |
| stim_write = bit'($urandom()); | |
| for (int unsigned k = 0; k < AddrWidth; k++) begin | |
| stim_addr[k] = bit'($urandom()); | |
| end | |
| while (stim_addr >= NumWords) begin | |
| for (int unsigned k = 0; k < AddrWidth; k++) begin | |
| stim_addr[k] = bit'($urandom()); | |
| end | |
| end | |
| for (int unsigned k = 0; k < DataWidth; k++) begin | |
| stim_data[k] = bit'($urandom()); | |
| end | |
| for (int unsigned k = 0; k < BeWidth; k++) begin | |
| stim_be[k] = bit'($urandom()); | |
| end | |
| req[i] <= #ApplTime 1'b1; | |
| we[i] <= #ApplTime stim_write; | |
| addr[i] <= #ApplTime stim_addr; | |
| wdata[i] <= #ApplTime stim_data; | |
| be[i] <= #ApplTime stim_be; | |
| @(posedge clk); | |
| req[i] <= #ApplTime 1'b0; | |
| we[i] <= #ApplTime 1'b0; | |
| addr[i] <= #ApplTime addr_t'(0); | |
| wdata[i] <= #ApplTime data_t'(0); | |
| be[i] <= #ApplTime be_t'(0); | |
| repeat ($urandom_range(0,5)) @(posedge clk); | |
| end | |
| done[i] <= 1'b1; | |
| end | |
| end | |
| initial begin: proc_golden_model | |
| failed_test = 0; | |
| for (int unsigned i = 0; i < NumWords; i++) begin | |
| for (int unsigned j = 0; j < DataWidth; j++) begin | |
| case (SimInit) | |
| "zeros": memory[i][j] = 1'b0; | |
| "ones": memory[i][j] = 1'b1; | |
| default: memory[i][j] = 1'bx; | |
| endcase | |
| end | |
| end | |
| @(posedge rst_n); | |
| forever begin | |
| @(posedge clk); | |
| for (int unsigned i = 0; i < NumPorts; i++) begin | |
| if (req[i] && we[i]) begin | |
| for (int unsigned j = 0; j < DataWidth; j++) begin | |
| if (be[i][j/ByteWidth]) begin | |
| memory[addr[i]][j] = wdata[i][j]; | |
| end | |
| end | |
| end | |
| end | |
| #TestTime; | |
| fork | |
| for (int unsigned i = 0; i < NumPorts; i++) begin | |
| check_read(i, addr[i]); | |
| end | |
| join_none | |
| end | |
| end | |
| task automatic check_read(input int unsigned port, input addr_t read_addr); | |
| if (req[port] && !we[port]) begin | |
| data_t exp_data = memory[read_addr]; | |
| if (Latency > 0) begin | |
| repeat (Latency) @(posedge clk); | |
| #TestTime; | |
| end | |
| for (int unsigned i = 0; i < DataWidth; i++) begin | |
| if (!$isunknown(exp_data[i])) begin | |
| assert(exp_data[i] === rdata[port][i]) else begin | |
| $warning("Port: %0d unexpected bit[%0h], Addr: %0h expected: %0h, measured: %0h", | |
| port, i, read_addr, exp_data[i], rdata[port][i]); | |
| failed_test++; | |
| end | |
| end | |
| end | |
| end | |
| endtask : check_read | |
| initial begin : proc_stop | |
| @(posedge rst_n); | |
| wait (&done); | |
| repeat (10) @(posedge clk); | |
| $info("Simulation done, errors: %0d", failed_test); | |
| $stop(); | |
| end | |
| tc_sram #( | |
| .NumWords ( NumWords ), | |
| .DataWidth ( DataWidth ), | |
| .ByteWidth ( ByteWidth ), | |
| .NumPorts ( NumPorts ), | |
| .Latency ( Latency ), | |
| .SimInit ( SimInit ), | |
| .PrintSimCfg ( 1'b1 ) | |
| ) i_tc_sram_dut ( | |
| .clk_i ( clk ), | |
| .rst_ni ( rst_n ), | |
| .req_i ( req ), | |
| .we_i ( we ), | |
| .addr_i ( addr ), | |
| .wdata_i ( wdata ), | |
| .be_i ( be ), | |
| .rdata_o ( rdata ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module pulp_clock_gating_async #( | |
| parameter int unsigned STAGES = 2 | |
| ) ( | |
| input logic clk_i, | |
| input logic rstn_i, | |
| input logic en_async_i, | |
| output logic en_ack_o, | |
| input logic test_en_i, | |
| output logic clk_o | |
| ); | |
| logic [STAGES-1:0] r_reg; | |
| assign en_ack_o = r_reg[STAGES-1]; | |
| always_ff @ (posedge clk_i or negedge rstn_i) begin | |
| if (!rstn_i) begin | |
| r_reg <= '0; | |
| end else begin | |
| r_reg <= {r_reg[STAGES-2:0], en_async_i}; | |
| end | |
| end | |
| pulp_clock_gating i_clk_gate ( | |
| .clk_i, | |
| .en_i ( r_reg[STAGES-1] ), | |
| .test_en_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cluster_clock_and2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_and2 i_tc_clk_and2 ( | |
| .clk0_i, | |
| .clk1_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module cluster_clock_buffer ( | |
| input logic clk_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_buffer i_tc_clk_buffer ( | |
| .clk_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module cluster_clock_gating ( | |
| input logic clk_i, | |
| input logic en_i, | |
| input logic test_en_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_gating i_tc_clk_gating ( | |
| .clk_i, | |
| .en_i, | |
| .test_en_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module cluster_clock_inverter ( | |
| input logic clk_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_inverter i_tc_clk_inverter ( | |
| .clk_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module cluster_clock_mux2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| input logic clk_sel_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_mux2 i_tc_clk_mux2 ( | |
| .clk0_i, | |
| .clk1_i, | |
| .clk_sel_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module cluster_clock_xor2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_xor2 i_tc_clk_xor2 ( | |
| .clk0_i, | |
| .clk1_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module pulp_clock_and2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_and2 i_tc_clk_and2 ( | |
| .clk0_i, | |
| .clk1_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module pulp_clock_buffer ( | |
| input logic clk_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_buffer i_tc_clk_buffer ( | |
| .clk_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module pulp_clock_gating ( | |
| input logic clk_i, | |
| input logic en_i, | |
| input logic test_en_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_gating i_tc_clk_gating ( | |
| .clk_i, | |
| .en_i, | |
| .test_en_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module pulp_clock_inverter ( | |
| input logic clk_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_inverter i_tc_clk_inverter ( | |
| .clk_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module pulp_clock_mux2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| input logic clk_sel_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_mux2 i_tc_clk_mux2 ( | |
| .clk0_i, | |
| .clk1_i, | |
| .clk_sel_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module pulp_clock_xor2 ( | |
| input logic clk0_i, | |
| input logic clk1_i, | |
| output logic clk_o | |
| ); | |
| tc_clk_xor2 i_tc_clk_xor2 ( | |
| .clk0_i, | |
| .clk1_i, | |
| .clk_o | |
| ); | |
| endmodule | |
| module pulp_clock_delay( | |
| input logic in_i, | |
| output logic out_o | |
| ); | |
| assign #(300ps) out_o = in_i; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module binary_to_gray #( | |
| parameter int N = -1 | |
| )( | |
| input logic [N-1:0] A, | |
| output logic [N-1:0] Z | |
| ); | |
| assign Z = A ^ (A >> 1); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| package cb_filter_pkg; | |
| typedef struct packed { | |
| int unsigned PermuteSeed; | |
| int unsigned XorSeed; | |
| } cb_seed_t; | |
| localparam cb_seed_t [2:0] EgSeeds = '{ | |
| '{PermuteSeed: 32'd299034753, XorSeed: 32'd4094834 }, | |
| '{PermuteSeed: 32'd19921030, XorSeed: 32'd995713 }, | |
| '{PermuteSeed: 32'd294388, XorSeed: 32'd65146511 } | |
| }; | |
| endpackage | |
| `begin_keywords "1800-2023" | |
| module cc_onehot #( | |
| parameter int unsigned Width = 4 | |
| ) ( | |
| input logic [Width-1:0] d_i, | |
| output logic is_onehot_o | |
| ); | |
| if (Width == 1) begin : gen_degenerated_onehot | |
| assign is_onehot_o = d_i; | |
| end else begin : gen_onehot | |
| localparam int LVLS = $clog2(Width) + 1; | |
| logic [LVLS-1:0][2**(LVLS-1)-1:0] sum, carry; | |
| logic [LVLS-2:0] carry_array; | |
| assign sum[0] = $unsigned(d_i); | |
| for (genvar i = 1; i < LVLS; i++) begin : gen_lvl | |
| localparam int unsigned LVLWidth = 2**LVLS / 2**i; | |
| for (genvar j = 0; j < LVLWidth; j+=2) begin : gen_width | |
| assign sum[i][j/2] = sum[i-1][j] ^ sum[i-1][j+1]; | |
| assign carry[i][j/2] = sum[i-1][j] & sum[i-1][j+1]; | |
| end | |
| assign carry_array[i-1] = |carry[i][LVLWidth/2-1:0]; | |
| end | |
| assign is_onehot_o = sum[LVLS-1][0] & ~|carry_array; | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| package cdc_reset_ctrlr_pkg; | |
| typedef enum logic[1:0] { | |
| CLEAR_PHASE_IDLE, | |
| CLEAR_PHASE_ISOLATE, | |
| CLEAR_PHASE_CLEAR, | |
| CLEAR_PHASE_POST_CLEAR | |
| } clear_seq_phase_e; | |
| endpackage : cdc_reset_ctrlr_pkg | |
| `begin_keywords "1800-2023" | |
| package cf_math_pkg; | |
| function automatic integer ceil_div (input longint dividend, input longint divisor); | |
| automatic longint remainder; | |
| if (dividend < 0) begin | |
| $fatal(1, "Dividend %0d is not a natural number!", dividend); | |
| end | |
| if (divisor < 0) begin | |
| $fatal(1, "Divisor %0d is not a natural number!", divisor); | |
| end | |
| if (divisor == 0) begin | |
| $fatal(1, "Division by zero!"); | |
| end | |
| remainder = dividend; | |
| for (ceil_div = 0; remainder > 0; ceil_div++) begin | |
| remainder = remainder - divisor; | |
| end | |
| endfunction | |
| function automatic integer unsigned idx_width (input integer unsigned num_idx); | |
| return (num_idx > 32'd1) ? unsigned'($clog2(num_idx)) : 32'd1; | |
| endfunction | |
| function automatic bit is_power_of_2 (input integer unsigned value); | |
| return (value != 0) && (value & (value - 1)) == 0; | |
| endfunction | |
| endpackage | |
| `begin_keywords "1800-2023" | |
| module clk_int_div #( | |
| parameter int unsigned DIV_VALUE_WIDTH = 4, | |
| parameter int unsigned DEFAULT_DIV_VALUE = 0, | |
| parameter bit ENABLE_CLOCK_IN_RESET = 1'b0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| input logic test_mode_en_i, | |
| input logic [DIV_VALUE_WIDTH-1:0] div_i, | |
| input logic div_valid_i, | |
| output logic div_ready_o, | |
| output logic clk_o, | |
| output logic [DIV_VALUE_WIDTH-1:0] cycl_count_o | |
| ); | |
| if ($clog2(DEFAULT_DIV_VALUE+1) > DIV_VALUE_WIDTH) begin : gen_elab_error | |
| $error("Default divider value %0d is not representable with the configured", | |
| "div value width of %0d bits.", | |
| DEFAULT_DIV_VALUE, DIV_VALUE_WIDTH); | |
| end | |
| localparam int unsigned DivResetValue = (DEFAULT_DIV_VALUE != 0)? DEFAULT_DIV_VALUE: 1; | |
| logic [DIV_VALUE_WIDTH-1:0] div_i_normalized; | |
| logic [DIV_VALUE_WIDTH-1:0] div_d, div_q; | |
| logic toggle_ffs_en; | |
| logic t_ff1_d, t_ff1_q; | |
| logic t_ff1_en; | |
| logic t_ff2_d, t_ff2_q; | |
| logic t_ff2_en; | |
| logic [DIV_VALUE_WIDTH-1:0] cycle_cntr_d, cycle_cntr_q; | |
| logic cycle_counter_en; | |
| logic clk_div_bypass_en_d, clk_div_bypass_en_q; | |
| logic odd_clk; | |
| logic even_clk; | |
| logic generated_clock; | |
| logic ungated_output_clock; | |
| logic use_odd_division_d, use_odd_division_q; | |
| logic gate_en_d, gate_en_q; | |
| logic gate_is_open_q; | |
| logic clear_cycle_counter; | |
| logic clear_toggle_flops; | |
| typedef enum logic[1:0] {IDLE, LOAD_DIV, WAIT_END_PERIOD} clk_gate_state_e; | |
| clk_gate_state_e clk_gate_state_d, clk_gate_state_q; | |
| assign div_i_normalized = (div_i != 0)? div_i : 1; | |
| always_comb begin | |
| div_d = div_q; | |
| div_ready_o = 1'b0; | |
| clk_div_bypass_en_d = clk_div_bypass_en_q; | |
| use_odd_division_d = use_odd_division_q; | |
| clk_gate_state_d = clk_gate_state_q; | |
| cycle_counter_en = 1'b1; | |
| clear_cycle_counter = 1'b0; | |
| clear_toggle_flops = 1'b0; | |
| toggle_ffs_en = 1'b1; | |
| gate_en_d = 1'b0; | |
| clk_gate_state_d = clk_gate_state_q; | |
| case (clk_gate_state_q) | |
| IDLE: begin | |
| gate_en_d = 1'b1; | |
| toggle_ffs_en = 1'b1; | |
| if (div_valid_i) begin | |
| if (div_i_normalized == div_q) begin | |
| div_ready_o = 1'b1; | |
| end else begin | |
| clk_gate_state_d = LOAD_DIV; | |
| gate_en_d = 1'b0; | |
| end | |
| end else if (!en_i && gate_is_open_q == 1'b0) begin | |
| cycle_counter_en = 1'b0; | |
| toggle_ffs_en = 1'b0; | |
| end | |
| end | |
| LOAD_DIV: begin | |
| gate_en_d = 1'b0; | |
| toggle_ffs_en = 1'b1; | |
| if ((gate_is_open_q == 1'b0) || clk_div_bypass_en_q) begin | |
| toggle_ffs_en = 1'b0; | |
| div_d = div_i_normalized; | |
| div_ready_o = 1'b1; | |
| clear_cycle_counter = 1'b1; | |
| clear_toggle_flops = 1'b1; | |
| use_odd_division_d = div_i_normalized[0]; | |
| clk_div_bypass_en_d = div_i_normalized == 1; | |
| clk_gate_state_d = WAIT_END_PERIOD; | |
| end | |
| end | |
| WAIT_END_PERIOD: begin | |
| gate_en_d = 1'b0; | |
| toggle_ffs_en = 1'b0; | |
| if (cycle_cntr_q == div_q - 1) begin | |
| clk_gate_state_d = IDLE; | |
| end | |
| end | |
| default: begin | |
| clk_gate_state_d = IDLE; | |
| end | |
| endcase | |
| end | |
| localparam logic UseOddDivisionResetValue = DEFAULT_DIV_VALUE[0]; | |
| localparam logic ClkDivBypassEnResetValue = (DEFAULT_DIV_VALUE < 2)? 1'b1: 1'b0; | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| use_odd_division_q <= UseOddDivisionResetValue; | |
| clk_div_bypass_en_q <= ClkDivBypassEnResetValue; | |
| div_q <= DivResetValue; | |
| clk_gate_state_q <= IDLE; | |
| gate_en_q <= ENABLE_CLOCK_IN_RESET; | |
| end else begin | |
| use_odd_division_q <= use_odd_division_d; | |
| clk_div_bypass_en_q <= clk_div_bypass_en_d; | |
| div_q <= div_d; | |
| clk_gate_state_q <= clk_gate_state_d; | |
| gate_en_q <= gate_en_d; | |
| end | |
| end | |
| always_comb begin | |
| cycle_cntr_d = cycle_cntr_q; | |
| if (clear_cycle_counter) begin | |
| cycle_cntr_d = '0; | |
| end else begin | |
| if (cycle_counter_en) begin | |
| if (clk_div_bypass_en_q || (cycle_cntr_q == div_q-1)) begin | |
| cycle_cntr_d = '0; | |
| end else begin | |
| cycle_cntr_d = cycle_cntr_q + 1; | |
| end | |
| end | |
| end | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| cycle_cntr_q <= '0; | |
| end else begin | |
| cycle_cntr_q <= cycle_cntr_d; | |
| end | |
| end | |
| assign cycl_count_o = cycle_cntr_q; | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| t_ff1_q = '0; | |
| end else begin | |
| if (t_ff1_en) begin | |
| t_ff1_q = t_ff1_d; | |
| end | |
| end | |
| end | |
| always_ff @(negedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| t_ff2_q = '0; | |
| end else begin | |
| if (t_ff2_en) begin | |
| t_ff2_q = t_ff2_d; | |
| end | |
| end | |
| end | |
| always_comb begin | |
| if (clear_toggle_flops) begin | |
| t_ff1_d = '0; | |
| t_ff2_d = '0; | |
| end else begin | |
| t_ff1_d = t_ff1_en? !t_ff1_q: t_ff1_q; | |
| t_ff2_d = t_ff2_en? !t_ff2_q: t_ff2_q; | |
| end | |
| end | |
| always_comb begin | |
| t_ff1_en = 1'b0; | |
| t_ff2_en = 1'b0; | |
| if (!clk_div_bypass_en_q && toggle_ffs_en) begin | |
| if (use_odd_division_q) begin | |
| t_ff1_en = (cycle_cntr_q == 0)? 1'b1: 1'b0; | |
| t_ff2_en = (cycle_cntr_q == (div_q+1)/2)? 1'b1: 1'b0; | |
| end else begin | |
| t_ff1_en = (cycle_cntr_q == 0 || cycle_cntr_q == div_q/2)? 1'b1: 1'b0; | |
| end | |
| end | |
| end | |
| assign even_clk = t_ff1_q; | |
| tc_clk_xor2 i_odd_clk_xor ( | |
| .clk0_i ( t_ff1_q ), | |
| .clk1_i ( t_ff2_q ), | |
| .clk_o ( odd_clk ) | |
| ); | |
| tc_clk_mux2 i_clk_mux ( | |
| .clk0_i ( even_clk ), | |
| .clk1_i ( odd_clk ), | |
| .clk_sel_i ( use_odd_division_q ), | |
| .clk_o ( generated_clock ) | |
| ); | |
| tc_clk_mux2 i_clk_bypass_mux ( | |
| .clk0_i ( generated_clock ), | |
| .clk1_i ( clk_i ), | |
| .clk_sel_i ( clk_div_bypass_en_q || test_mode_en_i ), | |
| .clk_o ( ungated_output_clock ) | |
| ); | |
| always_ff @(posedge ungated_output_clock, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| gate_is_open_q <= 1'b0; | |
| end else begin | |
| gate_is_open_q <= gate_en_q & en_i; | |
| end | |
| end | |
| tc_clk_gating #( | |
| .IS_FUNCTIONAL(1) | |
| ) i_clk_gate ( | |
| .clk_i ( ungated_output_clock ), | |
| .en_i ( gate_en_q & en_i ), | |
| .test_en_i ( test_mode_en_i ), | |
| .clk_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module credit_counter #( | |
| parameter int unsigned NumCredits = 0, | |
| parameter bit InitCreditEmpty = 1'b0, | |
| parameter int unsigned InitNumCredits = InitCreditEmpty ? '0 : NumCredits, | |
| parameter type credit_cnt_t = logic [$clog2(NumCredits):0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| output credit_cnt_t credit_o, | |
| input logic credit_give_i, | |
| input logic credit_take_i, | |
| input logic credit_init_i, | |
| output logic credit_left_o, | |
| output logic credit_crit_o, | |
| output logic credit_full_o | |
| ); | |
| credit_cnt_t credit_d, credit_q; | |
| logic increment, decrement; | |
| assign decrement = credit_take_i & ~credit_give_i; | |
| assign increment = ~credit_take_i & credit_give_i; | |
| always_comb begin | |
| credit_d = credit_q; | |
| if (decrement) credit_d = credit_q - 1; | |
| else if (increment) credit_d = credit_q + 1; | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| credit_q <= (InitNumCredits); | |
| end else begin | |
| if (credit_init_i) begin | |
| credit_q <= (InitNumCredits); | |
| end else begin | |
| credit_q <= (credit_d); | |
| end | |
| end | |
| end | |
| assign credit_o = credit_q; | |
| assign credit_left_o = (credit_q != '0); | |
| assign credit_crit_o = (credit_q == NumCredits-1); | |
| assign credit_full_o = (credit_q == NumCredits); | |
| CreditUnderflow: assert property (@(posedge clk_i) disable iff (( !rst_ni) !== '0) not (credit_o == '0 && decrement)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "CreditUnderflow", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/credit_counter.sv", 52); | |
| end | |
| CreditOverflow: assert property (@(posedge clk_i) disable iff (( !rst_ni) !== '0) not (credit_o == NumCredits && increment)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "CreditOverflow", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/credit_counter.sv", 53); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module delta_counter #( | |
| parameter int unsigned WIDTH = 4, | |
| parameter bit STICKY_OVERFLOW = 1'b0 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic clear_i, | |
| input logic en_i, | |
| input logic load_i, | |
| input logic down_i, | |
| input logic [WIDTH-1:0] delta_i, | |
| input logic [WIDTH-1:0] d_i, | |
| output logic [WIDTH-1:0] q_o, | |
| output logic overflow_o | |
| ); | |
| logic [WIDTH:0] counter_q, counter_d; | |
| if (STICKY_OVERFLOW) begin : gen_sticky_overflow | |
| logic overflow_d, overflow_q; | |
| always_ff @(posedge clk_i or negedge rst_ni) | |
| begin | |
| if(!rst_ni) begin | |
| overflow_q <= 1'b0; | |
| end else begin | |
| overflow_q <= overflow_d; | |
| end | |
| end | |
| always_comb begin | |
| overflow_d = overflow_q; | |
| if (clear_i || load_i) begin | |
| overflow_d = 1'b0; | |
| end else if (!overflow_q && en_i) begin | |
| if (down_i) begin | |
| overflow_d = delta_i > counter_q[WIDTH-1:0]; | |
| end else begin | |
| overflow_d = counter_q[WIDTH-1:0] > ({WIDTH{1'b1}} - delta_i); | |
| end | |
| end | |
| end | |
| assign overflow_o = overflow_q; | |
| end else begin : gen_transient_overflow | |
| assign overflow_o = counter_q[WIDTH]; | |
| end | |
| assign q_o = counter_q[WIDTH-1:0]; | |
| always_comb begin | |
| counter_d = counter_q; | |
| if (clear_i) begin | |
| counter_d = '0; | |
| end else if (load_i) begin | |
| counter_d = {1'b0, d_i}; | |
| end else if (en_i) begin | |
| if (down_i) begin | |
| counter_d = counter_q - delta_i; | |
| end else begin | |
| counter_d = counter_q + delta_i; | |
| end | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| counter_q <= '0; | |
| end else begin | |
| counter_q <= counter_d; | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| package ecc_pkg; | |
| function automatic int unsigned get_parity_width (input int unsigned data_width); | |
| int unsigned cw_width = 2; | |
| while (unsigned'(2**cw_width) < cw_width + data_width + 1) cw_width++; | |
| return cw_width; | |
| endfunction | |
| function automatic int unsigned get_cw_width (input int unsigned data_width); | |
| return data_width + get_parity_width(data_width); | |
| endfunction | |
| endpackage | |
| `begin_keywords "1800-2023" | |
| module edge_propagator_tx ( | |
| input logic clk_i, | |
| input logic rstn_i, | |
| input logic valid_i, | |
| input logic ack_i, | |
| output logic valid_o | |
| ); | |
| logic [1:0] sync_a; | |
| logic r_input_reg; | |
| logic s_input_reg_next; | |
| assign s_input_reg_next = valid_i | (r_input_reg & ~sync_a[0]); | |
| always @(negedge rstn_i or posedge clk_i) begin | |
| if (~rstn_i) begin | |
| r_input_reg <= 1'b0; | |
| sync_a <= 2'b00; | |
| end else begin | |
| r_input_reg <= s_input_reg_next; | |
| sync_a <= {ack_i,sync_a[1]}; | |
| end | |
| end | |
| assign valid_o = r_input_reg; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module exp_backoff #( | |
| parameter int unsigned Seed = 'hffff, | |
| parameter int unsigned MaxExp = 16 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic set_i, | |
| input logic clr_i, | |
| output logic is_zero_o | |
| ); | |
| localparam int unsigned WIDTH = 16; | |
| logic [WIDTH-1:0] lfsr_d, lfsr_q, cnt_d, cnt_q, mask_d, mask_q; | |
| logic lfsr; | |
| assign lfsr = lfsr_q[15-15] ^ | |
| lfsr_q[15-13] ^ | |
| lfsr_q[15-12] ^ | |
| lfsr_q[15-10]; | |
| assign lfsr_d = (set_i) ? {lfsr, lfsr_q[$high(lfsr_q):1]} : | |
| lfsr_q; | |
| assign mask_d = (clr_i) ? '0 : | |
| (set_i) ? {{(WIDTH-MaxExp){1'b0}},mask_q[MaxExp-2:0], 1'b1} : | |
| mask_q; | |
| assign cnt_d = (clr_i) ? '0 : | |
| (set_i) ? (mask_q & lfsr_q) : | |
| (!is_zero_o) ? cnt_q - 1'b1 : '0; | |
| assign is_zero_o = (cnt_q=='0); | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs | |
| if (!rst_ni) begin | |
| lfsr_q <= WIDTH'(Seed); | |
| mask_q <= '0; | |
| cnt_q <= '0; | |
| end else begin | |
| lfsr_q <= lfsr_d; | |
| mask_q <= mask_d; | |
| cnt_q <= cnt_d; | |
| end | |
| end | |
| initial begin | |
| max_exp_0: assert (MaxExp>0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "max_exp_0", "MaxExp must be greater than 0", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/exp_backoff.sv", 88); | |
| end | |
| end | |
| initial begin | |
| max_exp_gt_16: assert (MaxExp<=16) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "max_exp_gt_16", "MaxExp cannot be greater than 16", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/exp_backoff.sv", 89); | |
| end | |
| end | |
| initial begin | |
| seed_0: assert (Seed>0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "seed_0", "Zero seed is not allowed for LFSR", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/exp_backoff.sv", 90); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module fifo_v3 #( | |
| parameter bit FALL_THROUGH = 1'b0, | |
| parameter int unsigned DATA_WIDTH = 32, | |
| parameter int unsigned DEPTH = 8, | |
| parameter type dtype = logic [DATA_WIDTH-1:0], | |
| parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input logic testmode_i, | |
| output logic full_o, | |
| output logic empty_o, | |
| output logic [ADDR_DEPTH-1:0] usage_o, | |
| input dtype data_i, | |
| input logic push_i, | |
| output dtype data_o, | |
| input logic pop_i | |
| ); | |
| localparam int unsigned FifoDepth = (DEPTH > 0) ? DEPTH : 1; | |
| logic gate_clock; | |
| logic [ADDR_DEPTH - 1:0] read_pointer_n, read_pointer_q, write_pointer_n, write_pointer_q; | |
| logic [ADDR_DEPTH:0] status_cnt_n, status_cnt_q; | |
| dtype [FifoDepth - 1:0] mem_n, mem_q; | |
| assign usage_o = status_cnt_q[ADDR_DEPTH-1:0]; | |
| if (DEPTH == 0) begin : gen_pass_through | |
| assign empty_o = ~push_i; | |
| assign full_o = ~pop_i; | |
| end else begin : gen_fifo | |
| assign full_o = (status_cnt_q == FifoDepth[ADDR_DEPTH:0]); | |
| assign empty_o = (status_cnt_q == 0) & ~(FALL_THROUGH & push_i); | |
| end | |
| always_comb begin : read_write_comb | |
| read_pointer_n = read_pointer_q; | |
| write_pointer_n = write_pointer_q; | |
| status_cnt_n = status_cnt_q; | |
| data_o = (DEPTH == 0) ? data_i : mem_q[read_pointer_q]; | |
| mem_n = mem_q; | |
| gate_clock = 1'b1; | |
| if (push_i && ~full_o) begin | |
| mem_n[write_pointer_q] = data_i; | |
| gate_clock = 1'b0; | |
| if (write_pointer_q == FifoDepth[ADDR_DEPTH-1:0] - 1) | |
| write_pointer_n = '0; | |
| else | |
| write_pointer_n = write_pointer_q + 1; | |
| status_cnt_n = status_cnt_q + 1; | |
| end | |
| if (pop_i && ~empty_o) begin | |
| if (read_pointer_n == FifoDepth[ADDR_DEPTH-1:0] - 1) | |
| read_pointer_n = '0; | |
| else | |
| read_pointer_n = read_pointer_q + 1; | |
| status_cnt_n = status_cnt_q - 1; | |
| end | |
| if (push_i && pop_i && ~full_o && ~empty_o) | |
| status_cnt_n = status_cnt_q; | |
| if (FALL_THROUGH && (status_cnt_q == 0) && push_i) begin | |
| data_o = data_i; | |
| if (pop_i) begin | |
| status_cnt_n = status_cnt_q; | |
| read_pointer_n = read_pointer_q; | |
| write_pointer_n = write_pointer_q; | |
| end | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if(~rst_ni) begin | |
| read_pointer_q <= '0; | |
| write_pointer_q <= '0; | |
| status_cnt_q <= '0; | |
| end else begin | |
| if (flush_i) begin | |
| read_pointer_q <= '0; | |
| write_pointer_q <= '0; | |
| status_cnt_q <= '0; | |
| end else begin | |
| read_pointer_q <= read_pointer_n; | |
| write_pointer_q <= write_pointer_n; | |
| status_cnt_q <= status_cnt_n; | |
| end | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if(~rst_ni) begin | |
| mem_q <= {FifoDepth{dtype'('0)}}; | |
| end else if (!gate_clock) begin | |
| mem_q <= mem_n; | |
| end | |
| end | |
| initial begin | |
| depth_0: assert (DEPTH > 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "depth_0", "DEPTH must be greater than 0.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/fifo_v3.sv", 143); | |
| end | |
| end | |
| full_write: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (full_o |-> ~push_i)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "full_write", "Trying to push new data although the FIFO is full.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/fifo_v3.sv", 146); | |
| end | |
| empty_read: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (empty_o |-> ~pop_i)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "empty_read", "Trying to pop data although the FIFO is empty.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/fifo_v3.sv", 149); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module gray_to_binary #( | |
| parameter int N = -1 | |
| )( | |
| input logic [N-1:0] A, | |
| output logic [N-1:0] Z | |
| ); | |
| for (genvar i = 0; i < N; i++) | |
| assign Z[i] = ^A[N-1:i]; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module heaviside #( | |
| parameter int unsigned Width = 32, | |
| localparam int unsigned IdxWidth = cf_math_pkg::idx_width(Width), | |
| localparam type idx_t = logic [IdxWidth-1:0], | |
| localparam type mask_t = logic [Width-1:0] | |
| ) ( | |
| input idx_t x_i, | |
| output mask_t mask_o | |
| ); | |
| assign mask_o = (1 << (x_i + 1)) - 1; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module isochronous_4phase_handshake ( | |
| input logic src_clk_i, | |
| input logic src_rst_ni, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_clk_i, | |
| input logic dst_rst_ni, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| logic src_req_q, src_ack_q; | |
| logic dst_req_q, dst_ack_q; | |
| always_ff @(posedge (src_clk_i) or negedge (src_rst_ni)) begin | |
| if (!src_rst_ni) begin | |
| src_req_q <= (1'b0); | |
| end else begin | |
| if ((src_valid_i && src_ready_o)) begin | |
| src_req_q <= (~src_req_q); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (src_clk_i) or negedge (src_rst_ni)) begin | |
| if (!src_rst_ni) begin | |
| src_ack_q <= (1'b0); | |
| end else begin | |
| src_ack_q <= (dst_ack_q); | |
| end | |
| end | |
| assign src_ready_o = (src_req_q == src_ack_q); | |
| always_ff @(posedge (dst_clk_i) or negedge (dst_rst_ni)) begin | |
| if (!dst_rst_ni) begin | |
| dst_ack_q <= (1'b0); | |
| end else begin | |
| if ((dst_valid_o && dst_ready_i)) begin | |
| dst_ack_q <= (~dst_ack_q); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (dst_clk_i) or negedge (dst_rst_ni)) begin | |
| if (!dst_rst_ni) begin | |
| dst_req_q <= (1'b0); | |
| end else begin | |
| dst_req_q <= (src_req_q); | |
| end | |
| end | |
| assign dst_valid_o = (dst_req_q != dst_ack_q); | |
| src_valid_unstable: assert property (@(posedge src_clk_i) disable iff ((!src_rst_ni) !== '0) (src_valid_i && !src_ready_o |=> $stable(src_valid_i))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "src_valid_unstable", "src_valid_i is unstable", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/isochronous_4phase_handshake.sv", 75); | |
| end | |
| dst_valid_unstable: assert property (@(posedge dst_clk_i) disable iff ((!dst_rst_ni) !== '0) (dst_valid_o && !dst_ready_i |=> $stable(dst_valid_o))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "dst_valid_unstable", "dst_valid_o is unstable", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/isochronous_4phase_handshake.sv", 77); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module isochronous_spill_register #( | |
| parameter type T = logic, | |
| parameter bit Bypass = 1'b0 | |
| ) ( | |
| input logic src_clk_i, | |
| input logic src_rst_ni, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input T src_data_i, | |
| input logic dst_clk_i, | |
| input logic dst_rst_ni, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i, | |
| output T dst_data_o | |
| ); | |
| if (Bypass) begin : gen_bypass | |
| assign dst_valid_o = src_valid_i; | |
| assign src_ready_o = dst_ready_i; | |
| assign dst_data_o = src_data_i; | |
| end else begin : gen_isochronous_spill_register | |
| logic [1:0] rd_pointer_q, wr_pointer_q; | |
| always_ff @(posedge (src_clk_i) or negedge (src_rst_ni)) begin | |
| if (!src_rst_ni) begin | |
| wr_pointer_q <= ('0); | |
| end else begin | |
| if ((src_valid_i && src_ready_o)) begin | |
| wr_pointer_q <= (wr_pointer_q+1); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (dst_clk_i) or negedge (dst_rst_ni)) begin | |
| if (!dst_rst_ni) begin | |
| rd_pointer_q <= ('0); | |
| end else begin | |
| if ((dst_valid_o && dst_ready_i)) begin | |
| rd_pointer_q <= (rd_pointer_q+1); | |
| end | |
| end | |
| end | |
| T [1:0] mem_d, mem_q; | |
| always_ff @(posedge (src_clk_i) or negedge (src_rst_ni)) begin | |
| if (!src_rst_ni) begin | |
| mem_q <= ('0); | |
| end else begin | |
| if ((src_valid_i && src_ready_o)) begin | |
| mem_q <= (mem_d); | |
| end | |
| end | |
| end | |
| always_comb begin | |
| mem_d = mem_q; | |
| mem_d[wr_pointer_q[0]] = src_data_i; | |
| end | |
| assign src_ready_o = (rd_pointer_q ^ wr_pointer_q) != 2'b10; | |
| assign dst_valid_o = (rd_pointer_q ^ wr_pointer_q) != '0; | |
| assign dst_data_o = mem_q[rd_pointer_q[0]]; | |
| end | |
| src_valid_unstable: assert property (@(posedge src_clk_i) disable iff ((!src_rst_ni) !== '0) (src_valid_i && !src_ready_o |=> $stable(src_valid_i))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "src_valid_unstable", "src_valid_i is unstable", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/isochronous_spill_register.sv", 102); | |
| end | |
| dst_valid_unstable: assert property (@(posedge dst_clk_i) disable iff ((!dst_rst_ni) !== '0) (dst_valid_o && !dst_ready_i |=> $stable(dst_valid_o))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "dst_valid_unstable", "dst_valid_o is unstable", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/isochronous_spill_register.sv", 104); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module lfsr #( | |
| parameter int unsigned LfsrWidth = 64, | |
| parameter int unsigned OutWidth = 8, | |
| parameter logic [LfsrWidth-1:0] RstVal = '1, | |
| parameter int unsigned CipherLayers = 0, | |
| parameter bit CipherReg = 1'b1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| output logic [OutWidth-1:0] out_o | |
| ); | |
| localparam logic [63:0] Masks [4:64] = '{64'hC, | |
| 64'h1E, | |
| 64'h39, | |
| 64'h7E, | |
| 64'hFA, | |
| 64'h1FD, | |
| 64'h3FC, | |
| 64'h64B, | |
| 64'hD8F, | |
| 64'h1296, | |
| 64'h2496, | |
| 64'h4357, | |
| 64'h8679, | |
| 64'h1030E, | |
| 64'h206CD, | |
| 64'h403FE, | |
| 64'h807B8, | |
| 64'h1004B2, | |
| 64'h2006A8, | |
| 64'h4004B2, | |
| 64'h800B87, | |
| 64'h10004F3, | |
| 64'h200072D, | |
| 64'h40006AE, | |
| 64'h80009E3, | |
| 64'h10000583, | |
| 64'h20000C92, | |
| 64'h400005B6, | |
| 64'h80000EA6, | |
| 64'h1000007A3, | |
| 64'h200000ABF, | |
| 64'h400000842, | |
| 64'h80000123E, | |
| 64'h100000074E, | |
| 64'h2000000AE9, | |
| 64'h400000086A, | |
| 64'h8000001213, | |
| 64'h1000000077E, | |
| 64'h2000000123B, | |
| 64'h40000000877, | |
| 64'h8000000108D, | |
| 64'h100000000AE9, | |
| 64'h200000000E9F, | |
| 64'h4000000008A6, | |
| 64'h80000000191E, | |
| 64'h100000000090E, | |
| 64'h2000000000FB3, | |
| 64'h4000000000D7D, | |
| 64'h80000000016A5, | |
| 64'h10000000000B4B, | |
| 64'h200000000010AF, | |
| 64'h40000000000DDE, | |
| 64'h8000000000181A, | |
| 64'h100000000000B65, | |
| 64'h20000000000102D, | |
| 64'h400000000000CD5, | |
| 64'h8000000000024C1, | |
| 64'h1000000000000EF6, | |
| 64'h2000000000001363, | |
| 64'h4000000000000FCD, | |
| 64'h80000000000019E2}; | |
| localparam logic[15:0][3:0] Sbox4 = {4'h2, 4'h1, 4'h7, 4'h4, | |
| 4'h8, 4'hF, 4'hE, 4'h3, | |
| 4'hD, 4'hA, 4'h0, 4'h9, | |
| 4'hB, 4'h6, 4'h5, 4'hC }; | |
| localparam logic[63:0][5:0] Perm = {6'd63, 6'd47, 6'd31, 6'd15, 6'd62, 6'd46, 6'd30, 6'd14, | |
| 6'd61, 6'd45, 6'd29, 6'd13, 6'd60, 6'd44, 6'd28, 6'd12, | |
| 6'd59, 6'd43, 6'd27, 6'd11, 6'd58, 6'd42, 6'd26, 6'd10, | |
| 6'd57, 6'd41, 6'd25, 6'd09, 6'd56, 6'd40, 6'd24, 6'd08, | |
| 6'd55, 6'd39, 6'd23, 6'd07, 6'd54, 6'd38, 6'd22, 6'd06, | |
| 6'd53, 6'd37, 6'd21, 6'd05, 6'd52, 6'd36, 6'd20, 6'd04, | |
| 6'd51, 6'd35, 6'd19, 6'd03, 6'd50, 6'd34, 6'd18, 6'd02, | |
| 6'd49, 6'd33, 6'd17, 6'd01, 6'd48, 6'd32, 6'd16, 6'd00}; | |
| function automatic logic [63:0] sbox4_layer(logic [63:0] in); | |
| logic [63:0] out; | |
| out[0*4 +: 4] = Sbox4[in[0*4 +: 4]]; | |
| out[1*4 +: 4] = Sbox4[in[1*4 +: 4]]; | |
| out[2*4 +: 4] = Sbox4[in[2*4 +: 4]]; | |
| out[3*4 +: 4] = Sbox4[in[3*4 +: 4]]; | |
| out[4*4 +: 4] = Sbox4[in[4*4 +: 4]]; | |
| out[5*4 +: 4] = Sbox4[in[5*4 +: 4]]; | |
| out[6*4 +: 4] = Sbox4[in[6*4 +: 4]]; | |
| out[7*4 +: 4] = Sbox4[in[7*4 +: 4]]; | |
| out[8*4 +: 4] = Sbox4[in[8*4 +: 4]]; | |
| out[9*4 +: 4] = Sbox4[in[9*4 +: 4]]; | |
| out[10*4 +: 4] = Sbox4[in[10*4 +: 4]]; | |
| out[11*4 +: 4] = Sbox4[in[11*4 +: 4]]; | |
| out[12*4 +: 4] = Sbox4[in[12*4 +: 4]]; | |
| out[13*4 +: 4] = Sbox4[in[13*4 +: 4]]; | |
| out[14*4 +: 4] = Sbox4[in[14*4 +: 4]]; | |
| out[15*4 +: 4] = Sbox4[in[15*4 +: 4]]; | |
| return out; | |
| endfunction : sbox4_layer | |
| function automatic logic [63:0] perm_layer(logic [63:0] in); | |
| logic [63:0] out; | |
| out[Perm[0]] = in[0]; | |
| out[Perm[1]] = in[1]; | |
| out[Perm[2]] = in[2]; | |
| out[Perm[3]] = in[3]; | |
| out[Perm[4]] = in[4]; | |
| out[Perm[5]] = in[5]; | |
| out[Perm[6]] = in[6]; | |
| out[Perm[7]] = in[7]; | |
| out[Perm[8]] = in[8]; | |
| out[Perm[9]] = in[9]; | |
| out[Perm[10]] = in[10]; | |
| out[Perm[11]] = in[11]; | |
| out[Perm[12]] = in[12]; | |
| out[Perm[13]] = in[13]; | |
| out[Perm[14]] = in[14]; | |
| out[Perm[15]] = in[15]; | |
| out[Perm[16]] = in[16]; | |
| out[Perm[17]] = in[17]; | |
| out[Perm[18]] = in[18]; | |
| out[Perm[19]] = in[19]; | |
| out[Perm[20]] = in[20]; | |
| out[Perm[21]] = in[21]; | |
| out[Perm[22]] = in[22]; | |
| out[Perm[23]] = in[23]; | |
| out[Perm[24]] = in[24]; | |
| out[Perm[25]] = in[25]; | |
| out[Perm[26]] = in[26]; | |
| out[Perm[27]] = in[27]; | |
| out[Perm[28]] = in[28]; | |
| out[Perm[29]] = in[29]; | |
| out[Perm[30]] = in[30]; | |
| out[Perm[31]] = in[31]; | |
| out[Perm[32]] = in[32]; | |
| out[Perm[33]] = in[33]; | |
| out[Perm[34]] = in[34]; | |
| out[Perm[35]] = in[35]; | |
| out[Perm[36]] = in[36]; | |
| out[Perm[37]] = in[37]; | |
| out[Perm[38]] = in[38]; | |
| out[Perm[39]] = in[39]; | |
| out[Perm[40]] = in[40]; | |
| out[Perm[41]] = in[41]; | |
| out[Perm[42]] = in[42]; | |
| out[Perm[43]] = in[43]; | |
| out[Perm[44]] = in[44]; | |
| out[Perm[45]] = in[45]; | |
| out[Perm[46]] = in[46]; | |
| out[Perm[47]] = in[47]; | |
| out[Perm[48]] = in[48]; | |
| out[Perm[49]] = in[49]; | |
| out[Perm[50]] = in[50]; | |
| out[Perm[51]] = in[51]; | |
| out[Perm[52]] = in[52]; | |
| out[Perm[53]] = in[53]; | |
| out[Perm[54]] = in[54]; | |
| out[Perm[55]] = in[55]; | |
| out[Perm[56]] = in[56]; | |
| out[Perm[57]] = in[57]; | |
| out[Perm[58]] = in[58]; | |
| out[Perm[59]] = in[59]; | |
| out[Perm[60]] = in[60]; | |
| out[Perm[61]] = in[61]; | |
| out[Perm[62]] = in[62]; | |
| out[Perm[63]] = in[63]; | |
| return out; | |
| endfunction : perm_layer | |
| logic [LfsrWidth-1:0] lfsr_d, lfsr_q; | |
| assign lfsr_d = | |
| (en_i) ? (lfsr_q>>1) ^ ({LfsrWidth{lfsr_q[0]}} & Masks[LfsrWidth][LfsrWidth-1:0]) : lfsr_q; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs | |
| if (!rst_ni) begin | |
| lfsr_q <= LfsrWidth'(RstVal); | |
| end else begin | |
| lfsr_q <= lfsr_d; | |
| end | |
| end | |
| if (CipherLayers > unsigned'(0)) begin : g_cipher_layers | |
| logic [63:0] ciph_layer; | |
| localparam int unsigned NumRepl = ((64+LfsrWidth)/LfsrWidth); | |
| always_comb begin : p_ciph_layer | |
| automatic logic [63:0] tmp; | |
| tmp = 64'({NumRepl{lfsr_q}}); | |
| for(int unsigned k = 0; k < CipherLayers; k++) begin | |
| tmp = perm_layer(sbox4_layer(tmp)); | |
| end | |
| ciph_layer = tmp; | |
| end | |
| if (CipherReg) begin : g_cipher_reg | |
| logic [OutWidth-1:0] out_d, out_q; | |
| assign out_d = (en_i) ? ciph_layer[OutWidth-1:0] : out_q; | |
| assign out_o = out_q[OutWidth-1:0]; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs | |
| if (!rst_ni) begin | |
| out_q <= '0; | |
| end else begin | |
| out_q <= out_d; | |
| end | |
| end | |
| end else begin : g_no_out_reg | |
| assign out_o = ciph_layer[OutWidth-1:0]; | |
| end | |
| end else begin : g_no_cipher_layers | |
| assign out_o = lfsr_q[OutWidth-1:0]; | |
| end | |
| initial begin | |
| outwidth_gt_lfsrwidth: assert (OutWidth <= LfsrWidth) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "outwidth_gt_lfsrwidth", "OutWidth must be smaller equal the LfsrWidth.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr.sv", 297); | |
| end | |
| end | |
| initial begin | |
| rstval_0: assert (RstVal > unsigned'(0)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "rstval_0", "RstVal must be nonzero.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr.sv", 298); | |
| end | |
| end | |
| initial begin | |
| lfsrwidth_invalid: assert ((LfsrWidth >= $low(Masks)) && (LfsrWidth <= $high(Masks))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "lfsrwidth_invalid", "Unsupported LfsrWidth.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr.sv", 300); | |
| end | |
| end | |
| initial begin | |
| mask_invalid: assert (Masks[LfsrWidth][LfsrWidth-1]) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "mask_invalid", "LFSR mask is not correct. The MSB must be 1.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr.sv", 302); | |
| end | |
| end | |
| initial begin | |
| cipherlayers_invalid: assert ((CipherLayers > 0) && (LfsrWidth == 64) || (CipherLayers == 0)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "cipherlayers_invalid", "Use additional cipher layers only in conjunction with an LFSR width of 64 bit.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr.sv", 304); | |
| end | |
| end | |
| all_zero: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (en_i |-> lfsr_d)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "all_zero", "Lfsr must not be all-zero.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr.sv", 306); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module lfsr_16bit #( | |
| parameter logic [15:0] SEED = 8'b0, | |
| parameter int unsigned WIDTH = 16 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| output logic [WIDTH-1:0] refill_way_oh, | |
| output logic [$clog2(WIDTH)-1:0] refill_way_bin | |
| ); | |
| localparam int unsigned LogWidth = $clog2(WIDTH); | |
| logic [15:0] shift_d, shift_q; | |
| always_comb begin | |
| automatic logic shift_in; | |
| shift_in = !(shift_q[15] ^ shift_q[12] ^ shift_q[5] ^ shift_q[1]); | |
| shift_d = shift_q; | |
| if (en_i) | |
| shift_d = {shift_q[14:0], shift_in}; | |
| refill_way_oh = 'b0; | |
| refill_way_oh[shift_q[LogWidth-1:0]] = 1'b1; | |
| refill_way_bin = shift_q; | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ | |
| if(~rst_ni) begin | |
| shift_q <= SEED; | |
| end else begin | |
| shift_q <= shift_d; | |
| end | |
| end | |
| initial begin | |
| width_gt_16: assert (WIDTH <= 16) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "width_gt_16", "WIDTH needs to be less than 16 because of the 16-bit LFSR", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr_16bit.sv", 65); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module lfsr_8bit #( | |
| parameter logic [7:0] SEED = 8'b0, | |
| parameter int unsigned WIDTH = 8 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| output logic [ WIDTH-1:0] refill_way_oh, | |
| output logic [$clog2(WIDTH)-1:0] refill_way_bin | |
| ); | |
| localparam int unsigned LogWidth = $clog2(WIDTH); | |
| logic [7:0] shift_d, shift_q; | |
| always_comb begin | |
| automatic logic shift_in; | |
| shift_in = !(shift_q[7] ^ shift_q[3] ^ shift_q[2] ^ shift_q[1]); | |
| shift_d = shift_q; | |
| if (en_i) shift_d = {shift_q[6:0], shift_in}; | |
| refill_way_oh = 'b0; | |
| refill_way_oh[shift_q[LogWidth - 1:0]] = 1'b1; | |
| refill_way_bin = shift_q; | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : proc_ | |
| if (~rst_ni) begin | |
| shift_q <= SEED; | |
| end else begin | |
| shift_q <= shift_d; | |
| end | |
| end | |
| initial begin | |
| width_gt_8: assert (WIDTH <= 8) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "width_gt_8", "WIDTH needs to be less than 8 because of the 8-bit LFSR", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lfsr_8bit.sv", 58); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module lossy_valid_to_stream #( | |
| parameter int unsigned DATA_WIDTH = 32, | |
| parameter type T = logic [DATA_WIDTH-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic valid_i, | |
| input T data_i, | |
| output logic valid_o, | |
| input logic ready_i, | |
| output T data_o, | |
| output busy_o | |
| ); | |
| logic read_ptr_d, read_ptr_q; | |
| logic write_ptr_d, write_ptr_q; | |
| logic [1:0] pending_tx_counter_d, pending_tx_counter_q; | |
| T[1:0] mem_d, mem_q; | |
| assign valid_o = pending_tx_counter_q != 0 || valid_i; | |
| always_comb begin : write_logic | |
| write_ptr_d = write_ptr_q; | |
| mem_d = mem_q; | |
| if (valid_i) begin | |
| if (pending_tx_counter_q != 0 || !ready_i) begin | |
| if (pending_tx_counter_q == 2 && !ready_i) begin | |
| mem_d[write_ptr_q - 1'b1] = data_i; | |
| end else begin | |
| mem_d[write_ptr_q] = data_i; | |
| write_ptr_d = write_ptr_q + 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| always_comb begin : read_logic | |
| read_ptr_d = read_ptr_q; | |
| data_o = mem_q[read_ptr_q]; | |
| if (pending_tx_counter_q == 0 && valid_i) begin | |
| data_o = data_i; | |
| end else if (valid_o && ready_i) begin | |
| read_ptr_d = read_ptr_q + 1'b1; | |
| end | |
| end | |
| always_comb begin: count_transactions | |
| pending_tx_counter_d = pending_tx_counter_q; | |
| if (valid_i && valid_o && ready_i) begin | |
| pending_tx_counter_d = pending_tx_counter_q; | |
| end else if (valid_i && !(valid_o && ready_i)) begin | |
| if (pending_tx_counter_q != 2) begin | |
| pending_tx_counter_d = pending_tx_counter_q + 1'b1; | |
| end | |
| end else if (!valid_i && (valid_o && ready_i)) begin | |
| pending_tx_counter_d = pending_tx_counter_q - 1'b1; | |
| end | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| read_ptr_q <= '0; | |
| write_ptr_q <= '0; | |
| pending_tx_counter_q <= '0; | |
| mem_q <= {2{T'('0)}}; | |
| end else begin | |
| read_ptr_q <= read_ptr_d; | |
| write_ptr_q <= write_ptr_d; | |
| pending_tx_counter_q <= pending_tx_counter_d; | |
| mem_q <= mem_d; | |
| end | |
| end | |
| assign busy_o = pending_tx_counter_q != 0; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module mv_filter #( | |
| parameter int unsigned WIDTH = 4, | |
| parameter int unsigned THRESHOLD = 10 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic sample_i, | |
| input logic clear_i, | |
| input logic d_i, | |
| output logic q_o | |
| ); | |
| logic [WIDTH-1:0] counter_q, counter_d; | |
| logic d, q; | |
| assign q_o = q; | |
| always_comb begin | |
| counter_d = counter_q; | |
| d = q; | |
| if (counter_q >= THRESHOLD[WIDTH-1:0]) begin | |
| d = 1'b1; | |
| end else if (sample_i && d_i) begin | |
| counter_d = counter_q + 1; | |
| end | |
| if (clear_i) begin | |
| counter_d = '0; | |
| d = 1'b0; | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (~rst_ni) begin | |
| counter_q <= '0; | |
| q <= 1'b0; | |
| end else begin | |
| counter_q <= counter_d; | |
| q <= d; | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module onehot_to_bin #( | |
| parameter int unsigned ONEHOT_WIDTH = 16, | |
| parameter int unsigned BIN_WIDTH = ONEHOT_WIDTH == 1 ? 1 : $clog2(ONEHOT_WIDTH) | |
| ) ( | |
| input logic [ONEHOT_WIDTH-1:0] onehot, | |
| output logic [BIN_WIDTH-1:0] bin | |
| ); | |
| for (genvar j = 0; j < BIN_WIDTH; j++) begin : gen_jl | |
| logic [ONEHOT_WIDTH-1:0] tmp_mask; | |
| for (genvar i = 0; i < ONEHOT_WIDTH; i++) begin : gen_il | |
| logic [BIN_WIDTH-1:0] tmp_i; | |
| assign tmp_i = BIN_WIDTH'(i); | |
| assign tmp_mask[i] = tmp_i[j]; | |
| end | |
| assign bin[j] = |(tmp_mask & onehot); | |
| end | |
| final begin | |
| more_than_2_bits: assert ($onehot0(onehot) || $test$plusargs("disable_assert_final_checks")) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "more_than_2_bits", "More than two bit set in the one-hot signal", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/onehot_to_bin.sv", 35); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module plru_tree #( | |
| parameter int unsigned ENTRIES = 16 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic [ENTRIES-1:0] used_i, | |
| output logic [ENTRIES-1:0] plru_o | |
| ); | |
| localparam int unsigned LogEntries = $clog2(ENTRIES); | |
| logic [2*(ENTRIES-1)-1:0] plru_tree_q, plru_tree_d; | |
| always_comb begin : plru_replacement | |
| automatic int unsigned idx_base, shift; | |
| automatic logic new_index; | |
| idx_base = 0; | |
| shift = 0; | |
| new_index = 1'b0; | |
| plru_tree_d = plru_tree_q; | |
| for (int unsigned i = 0; i < ENTRIES; i++) begin | |
| if (used_i[i]) begin | |
| for (int unsigned lvl = 0; lvl < LogEntries; lvl++) begin | |
| idx_base = $unsigned((2**lvl)-1); | |
| shift = LogEntries - lvl; | |
| new_index = 1'(~(i >> (shift-1))); | |
| plru_tree_d[idx_base + (i >> shift)] = new_index; | |
| end | |
| end | |
| end | |
| end | |
| always_comb begin : plru_output | |
| automatic int unsigned idx_base, shift; | |
| automatic logic new_index; | |
| idx_base = 0; | |
| shift = 0; | |
| new_index = 1'b0; | |
| plru_o = '1; | |
| for (int unsigned i = 0; i < ENTRIES; i += 1) begin | |
| for (int unsigned lvl = 0; lvl < LogEntries; lvl++) begin | |
| idx_base = $unsigned((2**lvl)-1); | |
| shift = LogEntries - lvl; | |
| new_index = 1'(i >> (shift-1)); | |
| if (new_index) begin | |
| plru_o[i] &= plru_tree_q[idx_base + (i>>shift)]; | |
| end else begin | |
| plru_o[i] &= ~plru_tree_q[idx_base + (i>>shift)]; | |
| end | |
| end | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| plru_tree_q <= '0; | |
| end else begin | |
| plru_tree_q <= plru_tree_d; | |
| end | |
| end | |
| initial begin | |
| entries_not_power_of_2: assert (ENTRIES == 2**LogEntries) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "entries_not_power_of_2", "Entries must be a power of two", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/plru_tree.sv", 124); | |
| end | |
| end | |
| output_onehot: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) ($onehot0(plru_o))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "output_onehot", "More than one bit set in PLRU output.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/plru_tree.sv", 127); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module passthrough_stream_fifo #( | |
| parameter int unsigned Depth = 32'd8, | |
| parameter bit PrintInfo = 1'b0, | |
| parameter bit SameCycleRW = 1'b1, | |
| parameter type type_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input logic testmode_i, | |
| input type_t data_i, | |
| input logic valid_i, | |
| output logic ready_o, | |
| output type_t data_o, | |
| output logic valid_o, | |
| input logic ready_i | |
| ); | |
| localparam int unsigned PointerWidth = $clog2(Depth) + 1; | |
| logic [PointerWidth-1:0] read_ptr_d, read_ptr_q; | |
| logic [PointerWidth-1:0] write_ptr_d, write_ptr_q; | |
| type_t [Depth-1 :0] data_d, data_q; | |
| logic load_data; | |
| assign data_o = data_q[read_ptr_q[PointerWidth-2:0]]; | |
| always_comb begin | |
| load_data = 1'b0; | |
| read_ptr_d = read_ptr_q; | |
| write_ptr_d = write_ptr_q; | |
| data_d = data_q; | |
| if (flush_i) begin | |
| read_ptr_d = '0; | |
| write_ptr_d = '0; | |
| valid_o = 1'b0; | |
| ready_o = 1'b0; | |
| end else begin | |
| valid_o = read_ptr_q[PointerWidth-1] == write_ptr_q[PointerWidth-1] | |
| ? read_ptr_q[PointerWidth-2:0] != write_ptr_q[PointerWidth-2:0] : 1'b1; | |
| if (ready_i) begin | |
| if (read_ptr_q[PointerWidth-2:0] == (Depth-1)) begin | |
| read_ptr_d[PointerWidth-2:0] = '0; | |
| read_ptr_d[PointerWidth-1] = !read_ptr_q[PointerWidth-1]; | |
| end else begin | |
| read_ptr_d = read_ptr_q + 'd1; | |
| end | |
| end | |
| ready_o = (read_ptr_q[PointerWidth-1] == write_ptr_q[PointerWidth-1] | |
| ? 1'b1 : write_ptr_q[PointerWidth-2:0] != read_ptr_q[PointerWidth-2:0]) | |
| || (SameCycleRW && ready_i && valid_o); | |
| if (valid_i) begin | |
| load_data = 1'b1; | |
| data_d[write_ptr_q[PointerWidth-2:0]] = data_i; | |
| if (write_ptr_q[PointerWidth-2:0] == (Depth-1)) begin | |
| write_ptr_d[PointerWidth-2:0] = '0; | |
| write_ptr_d[PointerWidth-1] = !write_ptr_q[PointerWidth-1]; | |
| end else begin | |
| write_ptr_d = write_ptr_q + 'd1; | |
| end | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| read_ptr_q <= ('0); | |
| end else begin | |
| read_ptr_q <= (read_ptr_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| write_ptr_q <= ('0); | |
| end else begin | |
| write_ptr_q <= (write_ptr_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| data_q <= ('0); | |
| end else begin | |
| if (load_data) begin | |
| data_q <= (data_d); | |
| end | |
| end | |
| end | |
| CheckFullPush: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) not ((!ready_o & valid_i))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "CheckFullPush", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/passthrough_stream_fifo.sv", 118); | |
| end | |
| CheckEmptyPop: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) not ((!valid_o & ready_i))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "CheckEmptyPop", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/passthrough_stream_fifo.sv", 120); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module popcount #( | |
| parameter int unsigned INPUT_WIDTH = 256, | |
| localparam int unsigned PopcountWidth = $clog2(INPUT_WIDTH) + 1 | |
| ) ( | |
| input logic [ INPUT_WIDTH-1:0] data_i, | |
| output logic [PopcountWidth-1:0] popcount_o | |
| ); | |
| if (INPUT_WIDTH < 1) | |
| $error("INPUT_WIDTH must be larger or equal to 1."); | |
| always_comb begin | |
| popcount_o = 0; | |
| for (int i = 0; i < INPUT_WIDTH; i++) begin | |
| popcount_o += data_i[i]; | |
| end | |
| end | |
| endmodule : popcount | |
| `begin_keywords "1800-2023" | |
| module ring_buffer #( | |
| parameter int unsigned Depth = 32, | |
| parameter type data_t = logic, | |
| localparam int unsigned AddrWidth = cf_math_pkg::idx_width(Depth), | |
| localparam int unsigned StepWidth = cf_math_pkg::idx_width(Depth+1), | |
| localparam type addr_t = logic [AddrWidth-1:0], | |
| localparam type step_t = logic [StepWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic wvalid_i, | |
| output logic wready_o, | |
| input data_t wdata_i, | |
| input logic rvalid_i, | |
| output logic rready_o, | |
| input addr_t raddr_i, | |
| output data_t rdata_o, | |
| input logic advance_i, | |
| input step_t step_i, | |
| output addr_t wptr_o, | |
| output addr_t rptr_o, | |
| output logic full_o, | |
| output logic empty_o | |
| ); | |
| data_t [Depth-1:0] mem_d, mem_q; | |
| logic [AddrWidth:0] rptr_d, rptr_q; | |
| logic [AddrWidth:0] wptr_d, wptr_q; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| mem_q <= ('0); | |
| end else begin | |
| mem_q <= (mem_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| rptr_q <= ('0); | |
| end else begin | |
| rptr_q <= (rptr_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| wptr_q <= ('0); | |
| end else begin | |
| wptr_q <= (wptr_d); | |
| end | |
| end | |
| always_comb begin | |
| mem_d = mem_q; | |
| rptr_d = rptr_q; | |
| wptr_d = wptr_q; | |
| if (wvalid_i && wready_o) begin | |
| mem_d[wptr_q[AddrWidth-1:0]] = wdata_i; | |
| wptr_d = wptr_q + 1; | |
| end | |
| if (advance_i) begin | |
| rptr_d = rptr_q + step_i; | |
| end | |
| end | |
| assign wptr_o = wptr_q[AddrWidth-1:0]; | |
| assign rptr_o = rptr_q[AddrWidth-1:0]; | |
| assign empty_o = wptr_q == rptr_q; | |
| assign full_o = (wptr_q[AddrWidth-1:0] == rptr_q[AddrWidth-1:0]) && !empty_o; | |
| assign rready_o = ((rptr_o < wptr_o) && ((raddr_i >= rptr_o) && (raddr_i < wptr_o))) || | |
| ((rptr_o > wptr_o) && ((raddr_i >= rptr_o) || (raddr_i < wptr_o))) || | |
| ((rptr_o == wptr_o) && !empty_o); | |
| assign wready_o = !full_o; | |
| assign rdata_o = mem_q[raddr_i]; | |
| step_t max_step; | |
| always_comb begin | |
| if (rptr_q[AddrWidth] == wptr_d[AddrWidth]) | |
| max_step = wptr_d[AddrWidth-1:0] - rptr_q[AddrWidth-1:0]; | |
| else | |
| max_step = Depth - rptr_q[AddrWidth-1:0] + wptr_d[AddrWidth-1:0]; | |
| end | |
| ReadPtrOvertakesWritePtr: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (advance_i |-> step_i <= max_step)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "ReadPtrOvertakesWritePtr", "Attempting to increment rptr beyond wptr", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ring_buffer.sv", 140); | |
| end | |
| ; | |
| WritePtrOvertakesReadPtr: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (wvalid_i && wready_o |-> !((wptr_q[AddrWidth-1:0] == rptr_d[AddrWidth-1:0]) && !(wptr_q == rptr_d)))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "WritePtrOvertakesReadPtr", "Attempting to increment wptr beyond rptr", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ring_buffer.sv", 149); | |
| end | |
| ; | |
| ReadAddrOutOfBounds: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (rvalid_i && rready_o |-> ( ((rptr_o < wptr_o) && ((raddr_i >= rptr_o) && (raddr_i < wptr_o))) || ((rptr_o > wptr_o) && ((raddr_i >= rptr_o) || (raddr_i < wptr_o))) || ((rptr_o == wptr_o) && !empty_o) ))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "ReadAddrOutOfBounds", "raddr_i is not within the valid range defined by rptr_o and wptr_o", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ring_buffer.sv", 164); | |
| end | |
| ; | |
| WriteStable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) ((wvalid_i) && !(wready_o) |=> $stable((wdata_i) & ~( '0)))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "WriteStable", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ring_buffer.sv", 167); | |
| end | |
| ReadStable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) ((rvalid_i) && !(rready_o) |=> $stable((raddr_i) & ~( '0)))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "ReadStable", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ring_buffer.sv", 168); | |
| end | |
| initial begin | |
| CheckDepthPow2: assert (cf_math_pkg::is_power_of_2(Depth)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "CheckDepthPow2", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/ring_buffer.sv", 171); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module rr_arb_tree #( | |
| parameter int unsigned NumIn = 64, | |
| parameter int unsigned DataWidth = 32, | |
| parameter type DataType = logic [DataWidth-1:0], | |
| parameter bit ExtPrio = 1'b0, | |
| parameter bit AxiVldRdy = 1'b0, | |
| parameter bit LockIn = 1'b0, | |
| parameter bit FairArb = 1'b1, | |
| parameter int unsigned IdxWidth = (NumIn > 32'd1) ? unsigned'($clog2(NumIn)) : 32'd1, | |
| parameter type idx_t = logic [IdxWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input idx_t rr_i, | |
| input logic [NumIn-1:0] req_i, | |
| /*verilator lint_off UNOPTFLAT*/ | |
| output logic [NumIn-1:0] gnt_o, | |
| /*verilator lint_on UNOPTFLAT*/ | |
| input DataType [NumIn-1:0] data_i, | |
| output logic req_o, | |
| input logic gnt_i, | |
| output DataType data_o, | |
| output idx_t idx_o | |
| ); | |
| if (NumIn == unsigned'(1)) begin : gen_pass_through | |
| assign req_o = req_i[0]; | |
| assign gnt_o[0] = gnt_i; | |
| assign data_o = data_i[0]; | |
| assign idx_o = '0; | |
| end else begin : gen_arbiter | |
| localparam int unsigned NumLevels = unsigned'($clog2(NumIn)); | |
| /*verilator lint_off SPLITVAR*/ | |
| idx_t [2**NumLevels-2:0] index_nodes /*verilator split_var*/; | |
| DataType [2**NumLevels-2:0] data_nodes /*verilator split_var*/; | |
| logic [2**NumLevels-2:0] gnt_nodes /*verilator split_var*/; | |
| logic [2**NumLevels-2:0] req_nodes /*verilator split_var*/; | |
| /*verilator lint_on SPLITVAR*/ | |
| idx_t rr_q; | |
| logic [NumIn-1:0] req_d; | |
| assign req_o = req_nodes[0]; | |
| assign data_o = data_nodes[0]; | |
| assign idx_o = index_nodes[0]; | |
| if (ExtPrio) begin : gen_ext_rr | |
| assign rr_q = rr_i; | |
| assign req_d = req_i; | |
| end else begin : gen_int_rr | |
| idx_t rr_d; | |
| if (LockIn) begin : gen_lock | |
| logic lock_d, lock_q; | |
| logic [NumIn-1:0] req_q; | |
| assign lock_d = req_o & ~gnt_i; | |
| assign req_d = (lock_q) ? req_q : req_i; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : p_lock_reg | |
| if (!rst_ni) begin | |
| lock_q <= '0; | |
| end else begin | |
| if (flush_i) begin | |
| lock_q <= '0; | |
| end else begin | |
| lock_q <= lock_d; | |
| end | |
| end | |
| end | |
| lock: assert property (@(posedge clk_i) disable iff ((!rst_ni || flush_i) !== '0) (req_o && (!gnt_i && !flush_i) |=> idx_o == $past(idx_o))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "lock", "Lock implies same arbiter decision in next cycle if output is not ready.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 169); | |
| end | |
| logic [NumIn-1:0] req_tmp; | |
| assign req_tmp = req_q & req_i; | |
| lock_req: assume property (@(posedge clk_i) disable iff ((!rst_ni || flush_i) !== '0) (lock_d |=> req_tmp == req_q)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "lock_req", "It is disallowed to deassert unserved request signals when LockIn is enabled.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 174); | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : p_req_regs | |
| if (!rst_ni) begin | |
| req_q <= '0; | |
| end else begin | |
| if (flush_i) begin | |
| req_q <= '0; | |
| end else begin | |
| req_q <= req_d; | |
| end | |
| end | |
| end | |
| end else begin : gen_no_lock | |
| assign req_d = req_i; | |
| end | |
| if (FairArb) begin : gen_fair_arb | |
| logic [NumIn-1:0] upper_mask, lower_mask; | |
| idx_t upper_idx, lower_idx, next_idx; | |
| logic upper_empty, lower_empty; | |
| for (genvar i = 0; i < NumIn; i++) begin : gen_mask | |
| assign upper_mask[i] = (i > rr_q) ? req_d[i] : 1'b0; | |
| assign lower_mask[i] = (i <= rr_q) ? req_d[i] : 1'b0; | |
| end | |
| lzc #( | |
| .WIDTH ( NumIn ), | |
| .MODE ( 1'b0 ) | |
| ) i_lzc_upper ( | |
| .in_i ( upper_mask ), | |
| .cnt_o ( upper_idx ), | |
| .empty_o ( upper_empty ) | |
| ); | |
| lzc #( | |
| .WIDTH ( NumIn ), | |
| .MODE ( 1'b0 ) | |
| ) i_lzc_lower ( | |
| .in_i ( lower_mask ), | |
| .cnt_o ( lower_idx ), | |
| .empty_o ( ) | |
| ); | |
| assign next_idx = upper_empty ? lower_idx : upper_idx; | |
| assign rr_d = (gnt_i && req_o) ? next_idx : rr_q; | |
| end else begin : gen_unfair_arb | |
| assign rr_d = (gnt_i && req_o) ? ((rr_q == idx_t'(NumIn-1)) ? '0 : rr_q + 1'b1) : rr_q; | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : p_rr_regs | |
| if (!rst_ni) begin | |
| rr_q <= '0; | |
| end else begin | |
| if (flush_i) begin | |
| rr_q <= '0; | |
| end else begin | |
| rr_q <= rr_d; | |
| end | |
| end | |
| end | |
| end | |
| assign gnt_nodes[0] = gnt_i; | |
| for (genvar level = 0; unsigned'(level) < NumLevels; level++) begin : gen_levels | |
| for (genvar l = 0; l < 2**level; l++) begin : gen_level | |
| logic sel; | |
| localparam int unsigned Idx0 = 2**level-1+l; | |
| localparam int unsigned Idx1 = 2**(level+1)-1+l*2; | |
| if (unsigned'(level) == NumLevels-1) begin : gen_first_level | |
| if (unsigned'(l) * 2 < NumIn-1) begin : gen_reduce | |
| assign req_nodes[Idx0] = req_d[l*2] | req_d[l*2+1]; | |
| assign sel = ~req_d[l*2] | req_d[l*2+1] & rr_q[NumLevels-1-level]; | |
| assign index_nodes[Idx0] = idx_t'(sel); | |
| assign data_nodes[Idx0] = (sel) ? data_i[l*2+1] : data_i[l*2]; | |
| assign gnt_o[l*2] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l*2]) & ~sel; | |
| assign gnt_o[l*2+1] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l*2+1]) & sel; | |
| end | |
| if (unsigned'(l) * 2 == NumIn-1) begin : gen_first | |
| assign req_nodes[Idx0] = req_d[l*2]; | |
| assign index_nodes[Idx0] = '0; | |
| assign data_nodes[Idx0] = data_i[l*2]; | |
| assign gnt_o[l*2] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l*2]); | |
| end | |
| if (unsigned'(l) * 2 > NumIn-1) begin : gen_out_of_range | |
| assign req_nodes[Idx0] = 1'b0; | |
| assign index_nodes[Idx0] = idx_t'('0); | |
| assign data_nodes[Idx0] = DataType'('0); | |
| end | |
| end else begin : gen_other_levels | |
| assign req_nodes[Idx0] = req_nodes[Idx1] | req_nodes[Idx1+1]; | |
| assign sel = ~req_nodes[Idx1] | req_nodes[Idx1+1] & rr_q[NumLevels-1-level]; | |
| assign index_nodes[Idx0] = (sel) ? | |
| idx_t'({1'b1, index_nodes[Idx1+1][NumLevels-unsigned'(level)-2:0]}) : | |
| idx_t'({1'b0, index_nodes[Idx1][NumLevels-unsigned'(level)-2:0]}); | |
| assign data_nodes[Idx0] = (sel) ? data_nodes[Idx1+1] : data_nodes[Idx1]; | |
| assign gnt_nodes[Idx1] = gnt_nodes[Idx0] & ~sel; | |
| assign gnt_nodes[Idx1+1] = gnt_nodes[Idx0] & sel; | |
| end | |
| end | |
| end | |
| initial begin | |
| numin_0: assert (NumIn) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "numin_0", "Input must be at least one element wide.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 300); | |
| end | |
| end | |
| initial begin | |
| lockin_and_extprio: assert (!(LockIn && ExtPrio)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "lockin_and_extprio", "Cannot use LockIn feature together with external ExtPrio.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 302); | |
| end | |
| end | |
| hot_one: assert property (@(posedge clk_i) disable iff ((!rst_ni || flush_i) !== '0) ($onehot0(gnt_o))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "hot_one", "Grant signal must be hot1 or zero.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 305); | |
| end | |
| gnt0: assert property (@(posedge clk_i) disable iff ((!rst_ni || flush_i) !== '0) (|gnt_o |-> gnt_i)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "gnt0", "Grant out implies grant in.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 307); | |
| end | |
| gnt1: assert property (@(posedge clk_i) disable iff ((!rst_ni || flush_i) !== '0) (req_o |-> gnt_i |-> |gnt_o)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "gnt1", "Req out and grant in implies grant out.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 310); | |
| end | |
| gnt_idx: assert property (@(posedge clk_i) disable iff ((!rst_ni || flush_i) !== '0) (req_o |-> gnt_i |-> gnt_o[idx_o])) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "gnt_idx", "Idx_o / gnt_o do not match.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 313); | |
| end | |
| req0: assert property (@(posedge clk_i) disable iff ((!rst_ni || flush_i) !== '0) (|req_i |-> req_o)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "req0", "Req in implies req out.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 315); | |
| end | |
| req1: assert property (@(posedge clk_i) disable iff ((!rst_ni || flush_i) !== '0) (req_o |-> |req_i)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "req1", "Req out implies req in.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/rr_arb_tree.sv", 317); | |
| end | |
| end | |
| endmodule : rr_arb_tree | |
| `begin_keywords "1800-2023" | |
| module rstgen_bypass #( | |
| parameter int unsigned NumRegs = 4 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic rst_test_mode_ni, | |
| input logic test_mode_i, | |
| output logic rst_no, | |
| output logic init_no | |
| ); | |
| logic rst_n; | |
| logic [NumRegs-1:0] synch_regs_q; | |
| tc_clk_mux2 i_tc_clk_mux2_rst_n ( | |
| .clk0_i ( rst_ni ), | |
| .clk1_i ( rst_test_mode_ni ), | |
| .clk_sel_i ( test_mode_i ), | |
| .clk_o ( rst_n ) | |
| ); | |
| tc_clk_mux2 i_tc_clk_mux2_rst_no ( | |
| .clk0_i ( synch_regs_q[NumRegs-1] ), | |
| .clk1_i ( rst_test_mode_ni ), | |
| .clk_sel_i ( test_mode_i ), | |
| .clk_o ( rst_no ) | |
| ); | |
| tc_clk_mux2 i_tc_clk_mux2_init_no ( | |
| .clk0_i ( synch_regs_q[NumRegs-1] ), | |
| .clk1_i ( 1'b1 ), | |
| .clk_sel_i ( test_mode_i ), | |
| .clk_o ( init_no ) | |
| ); | |
| always @(posedge clk_i or negedge rst_n) begin | |
| if (~rst_n) begin | |
| synch_regs_q <= 0; | |
| end else begin | |
| synch_regs_q <= {synch_regs_q[NumRegs-2:0], 1'b1}; | |
| end | |
| end | |
| initial begin : p_assertions | |
| if (NumRegs < 1) $fatal(1, "At least one register is required."); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module serial_deglitch #( | |
| parameter int unsigned SIZE = 4 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| input logic d_i, | |
| output logic q_o | |
| ); | |
| logic [SIZE-1:0] count_q; | |
| logic q; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (~rst_ni) begin | |
| count_q <= '0; | |
| q <= 1'b0; | |
| end else begin | |
| if (en_i) begin | |
| if (d_i == 1'b1 && count_q != SIZE[SIZE-1:0]) begin | |
| count_q <= count_q + 1; | |
| end else if (d_i == 1'b0 && count_q != SIZE[SIZE-1:0]) begin | |
| count_q <= count_q - 1; | |
| end | |
| end | |
| end | |
| end | |
| always_comb begin | |
| if (count_q == SIZE[SIZE-1:0]) begin | |
| q_o = 1'b1; | |
| end else if (count_q == 0) begin | |
| q_o = 1'b0; | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module shift_reg #( | |
| parameter type dtype = logic, | |
| parameter int unsigned Depth = 1 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input dtype d_i, | |
| output dtype d_o | |
| ); | |
| shift_reg_gated #( | |
| .Depth(Depth), | |
| .dtype(dtype) | |
| ) i_shift_reg_gated ( | |
| .clk_i (clk_i), | |
| .rst_ni (rst_ni), | |
| .valid_i(1'b1), | |
| .data_i (d_i), | |
| .valid_o(), | |
| .data_o (d_o) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module shift_reg_gated #( | |
| parameter int unsigned Depth = 32'd8, | |
| parameter type dtype = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic valid_i, | |
| input dtype data_i, | |
| output logic valid_o, | |
| output dtype data_o | |
| ); | |
| if (Depth == 0) begin : gen_pass_through | |
| assign valid_o = valid_i; | |
| assign data_o = data_i; | |
| end else begin : gen_shift_reg | |
| logic [Depth-1 : 0] valid_d, valid_q; | |
| dtype [Depth-1 : 0] data_d, data_q; | |
| for (genvar i = 0; i < Depth; i++) begin : gen_regs | |
| if (i == 0) begin : gen_shift_in | |
| assign valid_d[i] = valid_i; | |
| assign data_d[i] = data_i; | |
| end else begin : gen_shift | |
| assign valid_d[i] = valid_q[i-1]; | |
| assign data_d[i] = data_q[i-1]; | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| valid_q[i] <= ('0); | |
| end else begin | |
| valid_q[i] <= (valid_d[i]); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| data_q[i] <= (dtype'('0)); | |
| end else begin | |
| if (valid_d[i]) begin | |
| data_q[i] <= (data_d[i]); | |
| end | |
| end | |
| end | |
| end | |
| assign valid_o = valid_q[Depth-1]; | |
| assign data_o = data_q[Depth-1]; | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module spill_register_flushable #( | |
| parameter type T = logic, | |
| parameter bit Bypass = 1'b0 | |
| ) ( | |
| input logic clk_i , | |
| input logic rst_ni , | |
| input logic valid_i , | |
| input logic flush_i , | |
| output logic ready_o , | |
| input T data_i , | |
| output logic valid_o , | |
| input logic ready_i , | |
| output T data_o | |
| ); | |
| if (Bypass) begin : gen_bypass | |
| assign valid_o = valid_i; | |
| assign ready_o = ready_i; | |
| assign data_o = data_i; | |
| end else begin : gen_spill_reg | |
| T a_data_q; | |
| logic a_full_q; | |
| logic a_fill, a_drain; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_data | |
| if (!rst_ni) | |
| a_data_q <= T'('0); | |
| else if (a_fill) | |
| a_data_q <= data_i; | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : ps_a_full | |
| if (!rst_ni) | |
| a_full_q <= 0; | |
| else if (a_fill || a_drain) | |
| a_full_q <= a_fill; | |
| end | |
| T b_data_q; | |
| logic b_full_q; | |
| logic b_fill, b_drain; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_data | |
| if (!rst_ni) | |
| b_data_q <= T'('0); | |
| else if (b_fill) | |
| b_data_q <= a_data_q; | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : ps_b_full | |
| if (!rst_ni) | |
| b_full_q <= 0; | |
| else if (b_fill || b_drain) | |
| b_full_q <= b_fill; | |
| end | |
| assign a_fill = valid_i && ready_o && (!flush_i); | |
| assign a_drain = (a_full_q && !b_full_q) || flush_i; | |
| assign b_fill = a_drain && (!ready_i) && (!flush_i); | |
| assign b_drain = (b_full_q && ready_i) || flush_i; | |
| assign ready_o = !a_full_q || !b_full_q; | |
| assign valid_o = a_full_q | b_full_q; | |
| assign data_o = b_full_q ? b_data_q : a_data_q; | |
| flush_valid: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (flush_i |-> ~valid_i)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "flush_valid", "Trying to flush and feed the spill register simultaneously. You will lose data!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/spill_register_flushable.sv", 100); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_demux #( | |
| parameter int unsigned N_OUP = 32'd1, | |
| parameter int unsigned LOG_N_OUP = (N_OUP > 32'd1) ? unsigned'($clog2(N_OUP)) : 1'b1 | |
| ) ( | |
| input logic inp_valid_i, | |
| output logic inp_ready_o, | |
| input logic [LOG_N_OUP-1:0] oup_sel_i, | |
| output logic [N_OUP-1:0] oup_valid_o, | |
| input logic [N_OUP-1:0] oup_ready_i | |
| ); | |
| always_comb begin | |
| oup_valid_o = '0; | |
| oup_valid_o[oup_sel_i] = inp_valid_i; | |
| end | |
| assign inp_ready_o = oup_ready_i[oup_sel_i]; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_filter ( | |
| input logic valid_i, | |
| output logic ready_o, | |
| input logic drop_i, | |
| output logic valid_o, | |
| input logic ready_i | |
| ); | |
| assign valid_o = drop_i ? 1'b0 : valid_i; | |
| assign ready_o = drop_i ? 1'b1 : ready_i; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_fork #( | |
| parameter int unsigned N_OUP = 0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic valid_i, | |
| output logic ready_o, | |
| output logic [N_OUP-1:0] valid_o, | |
| input logic [N_OUP-1:0] ready_i | |
| ); | |
| typedef enum logic {READY, WAIT} state_t; | |
| logic [N_OUP-1:0] oup_ready, | |
| all_ones; | |
| state_t inp_state_d, inp_state_q; | |
| always_comb begin | |
| inp_state_d = inp_state_q; | |
| unique case (inp_state_q) | |
| READY: begin | |
| if (valid_i) begin | |
| if (valid_o == all_ones && ready_i == all_ones) begin | |
| ready_o = 1'b1; | |
| end else begin | |
| ready_o = 1'b0; | |
| inp_state_d = WAIT; | |
| end | |
| end else begin | |
| ready_o = 1'b0; | |
| end | |
| end | |
| WAIT: begin | |
| if (valid_i && oup_ready == all_ones) begin | |
| ready_o = 1'b1; | |
| inp_state_d = READY; | |
| end else begin | |
| ready_o = 1'b0; | |
| end | |
| end | |
| default: begin | |
| inp_state_d = READY; | |
| ready_o = 1'b0; | |
| end | |
| endcase | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| inp_state_q <= READY; | |
| end else begin | |
| inp_state_q <= inp_state_d; | |
| end | |
| end | |
| for (genvar i = 0; i < N_OUP; i++) begin: gen_oup_state | |
| state_t oup_state_d, oup_state_q; | |
| always_comb begin | |
| oup_ready[i] = 1'b1; | |
| valid_o[i] = 1'b0; | |
| oup_state_d = oup_state_q; | |
| unique case (oup_state_q) | |
| READY: begin | |
| if (valid_i) begin | |
| valid_o[i] = 1'b1; | |
| if (ready_i[i]) begin | |
| if (!ready_o) begin | |
| oup_state_d = WAIT; | |
| end | |
| end else begin | |
| oup_ready[i] = 1'b0; | |
| end | |
| end | |
| end | |
| WAIT: begin | |
| if (valid_i && ready_o) begin | |
| oup_state_d = READY; | |
| end | |
| end | |
| default: begin | |
| oup_state_d = READY; | |
| end | |
| endcase | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| oup_state_q <= READY; | |
| end else begin | |
| oup_state_q <= oup_state_d; | |
| end | |
| end | |
| end | |
| assign all_ones = '1; | |
| initial begin | |
| n_oup_0: assert (N_OUP >= 1) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "n_oup_0", "Number of outputs must be at least 1!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_fork.sv", 128); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| interface STREAM_DV #( | |
| parameter type payload_t = logic | |
| )( | |
| input logic clk_i | |
| ); | |
| payload_t data; | |
| logic valid; | |
| logic ready; | |
| modport In ( | |
| output ready, | |
| input valid, data | |
| ); | |
| modport Out ( | |
| output valid, data, | |
| input ready | |
| ); | |
| modport Passive ( | |
| input valid, ready, data | |
| ); | |
| data_unstable: assert property (@(posedge clk_i) disable iff ((1'b0) !== '0) ((valid && !ready |=> $stable(data)))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "data_unstable", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_intf.sv", 46); | |
| end | |
| valid_unstable: assert property (@(posedge clk_i) disable iff ((1'b0) !== '0) ((valid && !ready |=> valid))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "valid_unstable", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_intf.sv", 47); | |
| end | |
| endinterface | |
| `begin_keywords "1800-2023" | |
| module stream_join_dynamic #( | |
| parameter int unsigned N_INP = 32'd0 | |
| ) ( | |
| input logic [N_INP-1:0] inp_valid_i, | |
| output logic [N_INP-1:0] inp_ready_o, | |
| input logic [N_INP-1:0] sel_i, | |
| output logic oup_valid_o, | |
| input logic oup_ready_i | |
| ); | |
| assign oup_valid_o = &(inp_valid_i | ~sel_i) && |sel_i; | |
| for (genvar i = 0; i < N_INP; i++) begin : gen_inp_ready | |
| assign inp_ready_o[i] = oup_valid_o & oup_ready_i & sel_i[i]; | |
| end | |
| initial begin | |
| n_inp_0: assert (N_INP >= 1) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "n_inp_0", "N_INP must be at least 1!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_join_dynamic.sv", 43); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_mux #( | |
| parameter type DATA_T = logic, | |
| parameter integer N_INP = 0, | |
| parameter integer LOG_N_INP = $clog2(N_INP) | |
| ) ( | |
| input DATA_T [N_INP-1:0] inp_data_i, | |
| input logic [N_INP-1:0] inp_valid_i, | |
| output logic [N_INP-1:0] inp_ready_o, | |
| input logic [LOG_N_INP-1:0] inp_sel_i, | |
| output DATA_T oup_data_o, | |
| output logic oup_valid_o, | |
| input logic oup_ready_i | |
| ); | |
| always_comb begin | |
| inp_ready_o = '0; | |
| inp_ready_o[inp_sel_i] = oup_ready_i; | |
| end | |
| assign oup_data_o = inp_data_i[inp_sel_i]; | |
| assign oup_valid_o = inp_valid_i[inp_sel_i]; | |
| initial begin | |
| n_inp_0: assert (N_INP >= 1) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "n_inp_0", "The number of inputs must be at least 1!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_mux.sv", 41); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_throttle #( | |
| parameter int unsigned MaxNumPending = 1, | |
| parameter int unsigned CntWidth = cf_math_pkg::idx_width(MaxNumPending), | |
| parameter type credit_t = logic [CntWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic req_valid_i, | |
| output logic req_valid_o, | |
| input logic req_ready_i, | |
| output logic req_ready_o, | |
| input logic rsp_valid_i, | |
| input logic rsp_ready_i, | |
| input credit_t credit_i | |
| ); | |
| credit_t credit_d, credit_q; | |
| logic credit_available; | |
| always_comb begin : proc_credit_counter | |
| credit_d = credit_q; | |
| if (req_ready_o & req_valid_o) begin | |
| credit_d = credit_d + 'd1; | |
| end | |
| if (rsp_valid_i & rsp_ready_i) begin | |
| credit_d = credit_d - 'd1; | |
| end | |
| end | |
| assign credit_available = credit_q <= (credit_i - 'd1); | |
| assign req_valid_o = req_valid_i & credit_available; | |
| assign req_ready_o = req_ready_i & credit_available; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| credit_q <= ('0); | |
| end else begin | |
| credit_q <= (credit_d); | |
| end | |
| end | |
| endmodule : stream_throttle | |
| `begin_keywords "1800-2023" | |
| module sub_per_hash #( | |
| parameter int unsigned InpWidth = 32'd11, | |
| parameter int unsigned HashWidth = 32'd5, | |
| parameter int unsigned NoRounds = 32'd1, | |
| parameter int unsigned PermuteKey = 32'd299034753, | |
| parameter int unsigned XorKey = 32'd4094834 | |
| ) ( | |
| input logic [InpWidth-1:0] data_i, | |
| output logic [HashWidth-1:0] hash_o, | |
| output logic [2**HashWidth-1:0] hash_onehot_o | |
| ); | |
| typedef int unsigned perm_lists_t [NoRounds][InpWidth]; | |
| perm_lists_t Permutations; | |
| assign Permutations = get_permutations(PermuteKey); | |
| typedef int unsigned xor_stages_t [NoRounds][InpWidth][3]; | |
| xor_stages_t XorStages; | |
| assign XorStages = get_xor_stages(XorKey); | |
| logic [NoRounds-1:0][InpWidth-1:0] permuted, xored; | |
| for (genvar r = 0; r < NoRounds; r++) begin : gen_round | |
| for (genvar i = 0; i < InpWidth ; i++) begin : gen_sub_per | |
| if (r == 0) begin : gen_input | |
| assign permuted[r][i] = data_i[Permutations[r][i]]; | |
| end else begin : gen_permutation | |
| assign permuted[r][i] = permuted[r-1][Permutations[r][i]]; | |
| end | |
| assign xored[r][i] = permuted[r][XorStages[r][i][0]] ^ | |
| permuted[r][XorStages[r][i][1]] ^ | |
| permuted[r][XorStages[r][i][2]]; | |
| end | |
| end | |
| assign hash_o = xored[NoRounds-1][HashWidth-1:0]; | |
| assign hash_onehot_o = 1 << hash_o; | |
| function automatic perm_lists_t get_permutations(input int unsigned seed); | |
| perm_lists_t indices; | |
| perm_lists_t perm_array; | |
| longint unsigned A = 2147483629; | |
| longint unsigned C = 2147483587; | |
| longint unsigned M = 2**31 - 1; | |
| longint unsigned index = 0; | |
| longint unsigned advance = 0; | |
| longint unsigned rand_number = (A * seed + C) % M; | |
| for (int unsigned r = 0; r < NoRounds; r++) begin | |
| for (int unsigned i = 0; i < InpWidth; i++) begin | |
| indices[r][i] = i; | |
| end | |
| for (int unsigned i = 0; i < InpWidth; i++) begin | |
| if (i > 0) begin | |
| rand_number = (A * rand_number + C) % M; | |
| index = rand_number % i; | |
| end | |
| if (i != index) begin | |
| perm_array[r][i] = perm_array[r][index]; | |
| perm_array[r][index] = indices[r][i]; | |
| end | |
| end | |
| rand_number = (A * rand_number + C) % M; | |
| advance = rand_number % NoRounds; | |
| for (int unsigned i = 0; i < advance; i++) begin | |
| rand_number = (A * rand_number + C) % M; | |
| end | |
| end | |
| return perm_array; | |
| endfunction : get_permutations | |
| function automatic xor_stages_t get_xor_stages(input int unsigned seed); | |
| xor_stages_t xor_array; | |
| longint unsigned A = 1664525; | |
| longint unsigned C = 1013904223; | |
| longint unsigned M = 2**32; | |
| longint unsigned index = 0; | |
| longint unsigned advance = 0; | |
| longint unsigned rand_number = (A * seed + C) % M; | |
| for (int unsigned r = 0; r < NoRounds; r++) begin | |
| for (int unsigned i = 0; i < InpWidth; i++) begin | |
| rand_number = (A * rand_number + C) % M; | |
| for (int unsigned j = 0; j < 3; j++) begin | |
| rand_number = (A * rand_number + C) % M; | |
| index = rand_number % InpWidth; | |
| xor_array[r][i][j] = index; | |
| end | |
| end | |
| rand_number = (A * rand_number + C) % M; | |
| advance = rand_number % NoRounds; | |
| for (int unsigned i = 0; i < advance; i++) begin | |
| rand_number = (A * rand_number + C) % M; | |
| end | |
| end | |
| return xor_array; | |
| endfunction : get_xor_stages | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module sync #( | |
| parameter int unsigned STAGES = 2, | |
| parameter bit ResetValue = 1'b0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic serial_i, | |
| output logic serial_o | |
| ); | |
| (* dont_touch = "true" *) | |
| (* async_reg = "true" *) | |
| logic [STAGES-1:0] reg_q; | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| reg_q <= {STAGES{ResetValue}}; | |
| end else begin | |
| reg_q <= {reg_q[STAGES-2:0], serial_i}; | |
| end | |
| end | |
| assign serial_o = reg_q[STAGES-1]; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module sync_wedge #( | |
| parameter int unsigned STAGES = 2 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| input logic serial_i, | |
| output logic r_edge_o, | |
| output logic f_edge_o, | |
| output logic serial_o | |
| ); | |
| logic clk; | |
| logic serial, serial_q; | |
| assign serial_o = serial_q; | |
| assign f_edge_o = (~serial) & serial_q; | |
| assign r_edge_o = serial & (~serial_q); | |
| sync #( | |
| .STAGES (STAGES) | |
| ) i_sync ( | |
| .clk_i, | |
| .rst_ni, | |
| .serial_i, | |
| .serial_o ( serial ) | |
| ); | |
| pulp_clock_gating i_pulp_clock_gating ( | |
| .clk_i, | |
| .en_i, | |
| .test_en_i ( 1'b0 ), | |
| .clk_o ( clk ) | |
| ); | |
| always_ff @(posedge clk, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| serial_q <= 1'b0; | |
| end else begin | |
| if (en_i) begin | |
| serial_q <= serial; | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| /*verilator lint_off UNUSED*/ | |
| module unread ( | |
| input logic d_i | |
| ); | |
| endmodule | |
| /*verilator lint_on UNUSED*/ | |
| `begin_keywords "1800-2023" | |
| (* no_ungroup *) | |
| module read #( | |
| parameter int unsigned Width = 1, | |
| parameter type T = logic [Width-1:0] | |
| ) ( | |
| input T d_i, | |
| output T d_o | |
| ); | |
| assign d_o = d_i; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module addr_decode_dync #( | |
| parameter int unsigned NoIndices = 32'd0, | |
| parameter int unsigned NoRules = 32'd0, | |
| parameter type addr_t = logic, | |
| parameter type rule_t = logic, | |
| parameter bit Napot = 0, | |
| parameter int unsigned IdxWidth = cf_math_pkg::idx_width(NoIndices), | |
| parameter type idx_t = logic [IdxWidth-1:0] | |
| ) ( | |
| input addr_t addr_i, | |
| input rule_t [NoRules-1:0] addr_map_i, | |
| output idx_t idx_o, | |
| output logic dec_valid_o, | |
| output logic dec_error_o, | |
| input logic en_default_idx_i, | |
| input idx_t default_idx_i, | |
| input logic config_ongoing_i | |
| ); | |
| logic [NoRules-1:0] matched_rules; | |
| always_comb begin | |
| matched_rules = '0; | |
| dec_valid_o = 1'b0; | |
| dec_error_o = (en_default_idx_i) ? 1'b0 : 1'b1; | |
| idx_o = (en_default_idx_i) ? default_idx_i : '0; | |
| for (int unsigned i = 0; i < NoRules; i++) begin | |
| if ( | |
| !Napot && (addr_i >= addr_map_i[i].start_addr) && | |
| ((addr_i < addr_map_i[i].end_addr) || (addr_map_i[i].end_addr == '0)) || | |
| Napot && (addr_map_i[i].start_addr & addr_map_i[i].end_addr) == | |
| (addr_i & addr_map_i[i].end_addr) | |
| ) begin | |
| matched_rules[i] = ~config_ongoing_i; | |
| dec_valid_o = ~config_ongoing_i; | |
| dec_error_o = 1'b0; | |
| idx_o = config_ongoing_i ? default_idx_i : idx_t'(addr_map_i[i].idx); | |
| end | |
| end | |
| end | |
| initial begin : proc_check_parameters | |
| addr_width_mismatch: assume ($bits(addr_i) == $bits(addr_map_i[0].start_addr)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "addr_width_mismatch", $sformatf("Input address has %d bits and address map has %d bits.", $bits(addr_i), $bits(addr_map_i[0].start_addr)), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/addr_decode_dync.sv", 129); | |
| end | |
| norules_0: assume (NoRules > 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "norules_0", $sformatf("At least one rule needed"), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/addr_decode_dync.sv", 130); | |
| end | |
| end | |
| final begin | |
| more_than_1_bit_set: assert ($onehot0(matched_rules) || config_ongoing_i || $test$plusargs("disable_assert_final_checks")) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "more_than_1_bit_set", "More than one bit set in the one-hot signal, matched_rules", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/addr_decode_dync.sv", 134); | |
| end | |
| end | |
| always_comb begin : proc_check_addr_map | |
| if (!$isunknown(addr_map_i) && ~config_ongoing_i) begin | |
| for (int unsigned i = 0; i < NoRules; i++) begin | |
| check_start: assume (Napot || addr_map_i[i].start_addr < addr_map_i[i].end_addr || addr_map_i[i].end_addr == '0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "check_start", $sformatf("This rule has a higher start than end address!!!\n\ | |
| Violating rule %d.\n\ | |
| Rule> IDX: %h START: %h END: %h\n\ | |
| #####################################################", i ,addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/addr_decode_dync.sv", 154); | |
| end | |
| for (int unsigned j = i + 1; j < NoRules; j++) begin | |
| check_overlap: assume (Napot || !((addr_map_i[j].start_addr < addr_map_i[i].end_addr) && (addr_map_i[j].end_addr > addr_map_i[i].start_addr)) || !((addr_map_i[i].end_addr == '0) && (addr_map_i[j].end_addr > addr_map_i[i].start_addr)) || !((addr_map_i[j].start_addr < addr_map_i[i].end_addr) && (addr_map_i[j].end_addr == '0))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "check_overlap", $sformatf("Overlapping address region found!!!\n\ | |
| Rule %d: IDX: %h START: %h END: %h\n\ | |
| Rule %d: IDX: %h START: %h END: %h\n\ | |
| #####################################################", i, addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr, j, addr_map_i[j].idx, addr_map_i[j].start_addr, addr_map_i[j].end_addr), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/addr_decode_dync.sv", 169); | |
| end | |
| end | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module boxcar #( | |
| parameter int unsigned Width = 32, | |
| localparam int unsigned IdxWidth = cf_math_pkg::idx_width(Width), | |
| localparam type idx_t = logic [IdxWidth-1:0], | |
| localparam type mask_t = logic [Width-1:0] | |
| ) ( | |
| input idx_t lsb_i, | |
| input idx_t msb_i, | |
| output mask_t mask_o | |
| ); | |
| mask_t low_mask, high_mask_n; | |
| heaviside #(.Width(Width)) i_lo (.x_i(lsb_i), .mask_o(low_mask)); | |
| heaviside #(.Width(Width)) i_hi (.x_i(msb_i), .mask_o(high_mask_n)); | |
| assign mask_o = ~low_mask & high_mask_n; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| /*verilator lint_off DECLFILENAME*/ | |
| module cdc_2phase #( | |
| parameter type T = logic | |
| )( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input T src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| output T dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| (* dont_touch = "true" *) logic async_req; | |
| (* dont_touch = "true" *) logic async_ack; | |
| (* dont_touch = "true" *) T async_data; | |
| cdc_2phase_src #(.T(T)) i_src ( | |
| .rst_ni ( src_rst_ni ), | |
| .clk_i ( src_clk_i ), | |
| .data_i ( src_data_i ), | |
| .valid_i ( src_valid_i ), | |
| .ready_o ( src_ready_o ), | |
| .async_req_o ( async_req ), | |
| .async_ack_i ( async_ack ), | |
| .async_data_o ( async_data ) | |
| ); | |
| cdc_2phase_dst #(.T(T)) i_dst ( | |
| .rst_ni ( dst_rst_ni ), | |
| .clk_i ( dst_clk_i ), | |
| .data_o ( dst_data_o ), | |
| .valid_o ( dst_valid_o ), | |
| .ready_i ( dst_ready_i ), | |
| .async_req_i ( async_req ), | |
| .async_ack_o ( async_ack ), | |
| .async_data_i ( async_data ) | |
| ); | |
| endmodule | |
| module cdc_2phase_src #( | |
| parameter type T = logic | |
| )( | |
| input logic rst_ni, | |
| input logic clk_i, | |
| input T data_i, | |
| input logic valid_i, | |
| output logic ready_o, | |
| output logic async_req_o, | |
| input logic async_ack_i, | |
| output T async_data_o | |
| ); | |
| (* dont_touch = "true" *) | |
| logic req_src_q, ack_src_q, ack_q; | |
| (* dont_touch = "true" *) | |
| T data_src_q; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| req_src_q <= 0; | |
| data_src_q <= T'('0); | |
| end else if (valid_i && ready_o) begin | |
| req_src_q <= ~req_src_q; | |
| data_src_q <= data_i; | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| ack_src_q <= 0; | |
| ack_q <= 0; | |
| end else begin | |
| ack_src_q <= async_ack_i; | |
| ack_q <= ack_src_q; | |
| end | |
| end | |
| assign ready_o = (req_src_q == ack_q); | |
| assign async_req_o = req_src_q; | |
| assign async_data_o = data_src_q; | |
| endmodule | |
| module cdc_2phase_dst #( | |
| parameter type T = logic | |
| )( | |
| input logic rst_ni, | |
| input logic clk_i, | |
| output T data_o, | |
| output logic valid_o, | |
| input logic ready_i, | |
| input logic async_req_i, | |
| output logic async_ack_o, | |
| input T async_data_i | |
| ); | |
| (* dont_touch = "true" *) | |
| (* async_reg = "true" *) | |
| logic req_dst_q, req_q0, req_q1, ack_dst_q; | |
| (* dont_touch = "true" *) | |
| T data_dst_q; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| ack_dst_q <= 0; | |
| end else if (valid_o && ready_i) begin | |
| ack_dst_q <= ~ack_dst_q; | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| data_dst_q <= T'('0); | |
| end else if (req_q0 != req_q1 && !valid_o) begin | |
| data_dst_q <= async_data_i; | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| req_dst_q <= 0; | |
| req_q0 <= 0; | |
| req_q1 <= 0; | |
| end else begin | |
| req_dst_q <= async_req_i; | |
| req_q0 <= req_dst_q; | |
| req_q1 <= req_q0; | |
| end | |
| end | |
| assign valid_o = (ack_dst_q != req_q1); | |
| assign data_o = data_dst_q; | |
| assign async_ack_o = ack_dst_q; | |
| endmodule | |
| /*verilator lint_on DECLFILENAME*/ | |
| `begin_keywords "1800-2023" | |
| /*verilator lint_off DECLFILENAME*/ | |
| module cdc_4phase #( | |
| parameter type T = logic, | |
| parameter bit DECOUPLED = 1'b1, | |
| parameter bit SEND_RESET_MSG = 1'b0, | |
| parameter T RESET_MSG = T'('0) | |
| )( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input T src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| output T dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| (* dont_touch = "true" *) logic async_req; | |
| (* dont_touch = "true" *) logic async_ack; | |
| (* dont_touch = "true" *) T async_data; | |
| cdc_4phase_src #( | |
| .T(T), | |
| .DECOUPLED(DECOUPLED), | |
| .SEND_RESET_MSG(SEND_RESET_MSG), | |
| .RESET_MSG(RESET_MSG) | |
| ) i_src ( | |
| .rst_ni ( src_rst_ni ), | |
| .clk_i ( src_clk_i ), | |
| .data_i ( src_data_i ), | |
| .valid_i ( src_valid_i ), | |
| .ready_o ( src_ready_o ), | |
| .async_req_o ( async_req ), | |
| .async_ack_i ( async_ack ), | |
| .async_data_o ( async_data ) | |
| ); | |
| cdc_4phase_dst #(.T(T), .DECOUPLED(DECOUPLED)) i_dst ( | |
| .rst_ni ( dst_rst_ni ), | |
| .clk_i ( dst_clk_i ), | |
| .data_o ( dst_data_o ), | |
| .valid_o ( dst_valid_o ), | |
| .ready_i ( dst_ready_i ), | |
| .async_req_i ( async_req ), | |
| .async_ack_o ( async_ack ), | |
| .async_data_i ( async_data ) | |
| ); | |
| endmodule | |
| module cdc_4phase_src #( | |
| parameter type T = logic, | |
| parameter int unsigned SYNC_STAGES = 2, | |
| parameter bit DECOUPLED = 1'b1, | |
| parameter bit SEND_RESET_MSG = 1'b0, | |
| parameter T RESET_MSG = T'('0) | |
| )( | |
| input logic rst_ni, | |
| input logic clk_i, | |
| input T data_i, | |
| input logic valid_i, | |
| output logic ready_o, | |
| output logic async_req_o, | |
| input logic async_ack_i, | |
| output T async_data_o | |
| ); | |
| (* dont_touch = "true" *) | |
| logic req_src_d, req_src_q; | |
| (* dont_touch = "true" *) | |
| T data_src_d, data_src_q; | |
| (* dont_touch = "true" *) | |
| logic ack_synced; | |
| typedef enum logic[1:0] {IDLE, WAIT_ACK_ASSERT, WAIT_ACK_DEASSERT} state_e; | |
| state_e state_d, state_q; | |
| sync #( | |
| .STAGES(SYNC_STAGES) | |
| ) i_sync( | |
| .clk_i, | |
| .rst_ni, | |
| .serial_i( async_ack_i ), | |
| .serial_o( ack_synced ) | |
| ); | |
| always_comb begin | |
| state_d = state_q; | |
| req_src_d = 1'b0; | |
| data_src_d = data_src_q; | |
| ready_o = 1'b0; | |
| case (state_q) | |
| IDLE: begin | |
| if (DECOUPLED) begin | |
| ready_o = 1'b1; | |
| end else begin | |
| ready_o = 1'b0; | |
| end | |
| if (valid_i) begin | |
| data_src_d = data_i; | |
| req_src_d = 1'b1; | |
| state_d = WAIT_ACK_ASSERT; | |
| end | |
| end | |
| WAIT_ACK_ASSERT: begin | |
| req_src_d = 1'b1; | |
| if (ack_synced == 1'b1) begin | |
| req_src_d = 1'b0; | |
| state_d = WAIT_ACK_DEASSERT; | |
| end | |
| end | |
| WAIT_ACK_DEASSERT: begin | |
| if (ack_synced == 1'b0) begin | |
| state_d = IDLE; | |
| if (!DECOUPLED) begin | |
| ready_o = 1'b1; | |
| end | |
| end | |
| end | |
| default: begin | |
| state_d = IDLE; | |
| end | |
| endcase | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| state_q <= IDLE; | |
| end else begin | |
| state_q <= state_d; | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| if (SEND_RESET_MSG) begin | |
| req_src_q <= 1'b1; | |
| data_src_q <= RESET_MSG; | |
| end else begin | |
| req_src_q <= 1'b0; | |
| data_src_q <= T'('0); | |
| end | |
| end else begin | |
| req_src_q <= req_src_d; | |
| data_src_q <= data_src_d; | |
| end | |
| end | |
| assign async_req_o = req_src_q; | |
| assign async_data_o = data_src_q; | |
| endmodule | |
| module cdc_4phase_dst #( | |
| parameter type T = logic, | |
| parameter int unsigned SYNC_STAGES = 2, | |
| parameter bit DECOUPLED = 1 | |
| )( | |
| input logic rst_ni, | |
| input logic clk_i, | |
| output T data_o, | |
| output logic valid_o, | |
| input logic ready_i, | |
| input logic async_req_i, | |
| output logic async_ack_o, | |
| input T async_data_i | |
| ); | |
| (* dont_touch = "true" *) | |
| logic ack_dst_d, ack_dst_q; | |
| (* dont_touch = "true" *) | |
| logic req_synced; | |
| logic data_valid; | |
| logic output_ready; | |
| typedef enum logic[1:0] {IDLE, WAIT_DOWNSTREAM_ACK, WAIT_REQ_DEASSERT} state_e; | |
| state_e state_d, state_q; | |
| sync #( | |
| .STAGES(SYNC_STAGES) | |
| ) i_sync( | |
| .clk_i, | |
| .rst_ni, | |
| .serial_i( async_req_i ), | |
| .serial_o( req_synced ) | |
| ); | |
| always_comb begin | |
| state_d = state_q; | |
| data_valid = 1'b0; | |
| ack_dst_d = 1'b0; | |
| case (state_q) | |
| IDLE: begin | |
| if (req_synced == 1'b1) begin | |
| data_valid = 1'b1; | |
| if (output_ready == 1'b1) begin | |
| state_d = WAIT_REQ_DEASSERT; | |
| end else begin | |
| state_d = WAIT_DOWNSTREAM_ACK; | |
| end | |
| end | |
| end | |
| WAIT_DOWNSTREAM_ACK: begin | |
| data_valid = 1'b1; | |
| if (output_ready == 1'b1) begin | |
| state_d = WAIT_REQ_DEASSERT; | |
| ack_dst_d = 1'b1; | |
| end | |
| end | |
| WAIT_REQ_DEASSERT: begin | |
| ack_dst_d = 1'b1; | |
| if (req_synced == 1'b0) begin | |
| ack_dst_d = 1'b0; | |
| state_d = IDLE; | |
| end | |
| end | |
| default: begin | |
| state_d = IDLE; | |
| end | |
| endcase | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| state_q <= IDLE; | |
| end else begin | |
| state_q <= state_d; | |
| end | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| ack_dst_q <= 1'b0; | |
| end else begin | |
| ack_dst_q <= ack_dst_d; | |
| end | |
| end | |
| if (DECOUPLED) begin : gen_decoupled | |
| spill_register #( | |
| .T(T), | |
| .Bypass(1'b0) | |
| ) i_spill_register ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i(data_valid), | |
| .ready_o(output_ready), | |
| .data_i(async_data_i), | |
| .valid_o, | |
| .ready_i, | |
| .data_o | |
| ); | |
| end else begin : gen_not_decoupled | |
| assign valid_o = data_valid; | |
| assign output_ready = ready_i; | |
| assign data_o = async_data_i; | |
| end | |
| assign async_ack_o = ack_dst_q; | |
| endmodule | |
| /*verilator lint_on DECLFILENAME*/ | |
| `begin_keywords "1800-2023" | |
| module clk_int_div_static #( | |
| parameter int unsigned DIV_VALUE = 1, | |
| parameter bit ENABLE_CLOCK_IN_RESET = 1'b1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| input logic test_mode_en_i, | |
| output logic clk_o | |
| ); | |
| if (DIV_VALUE == 0) begin : gen_elab_error | |
| $error("DIV_VALUE must be strictly larger than 0."); | |
| end | |
| localparam int unsigned DivValueWidth = $clog2(DIV_VALUE+1); | |
| logic [DivValueWidth-1:0] div_value; | |
| assign div_value = DIV_VALUE; | |
| clk_int_div #( | |
| .DIV_VALUE_WIDTH ( DivValueWidth ), | |
| .DEFAULT_DIV_VALUE ( DIV_VALUE ), | |
| .ENABLE_CLOCK_IN_RESET ( ENABLE_CLOCK_IN_RESET ) | |
| ) i_clk_int_div ( | |
| .clk_i, | |
| .rst_ni, | |
| .en_i, | |
| .test_mode_en_i, | |
| .div_i ( div_value ), | |
| .div_valid_i ( 1'b0 ), | |
| .div_ready_o ( ), | |
| .clk_o, | |
| .cycl_count_o ( ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module trip_counter #( | |
| parameter int unsigned WIDTH = 4 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| input logic [WIDTH-1:0] delta_i, | |
| input logic [WIDTH-1:0] bound_i, | |
| output logic [WIDTH-1:0] q_o, | |
| output logic last_o, | |
| output logic trip_o | |
| ); | |
| delta_counter #( | |
| .WIDTH(WIDTH) | |
| ) i_delta_counter ( | |
| .clk_i(clk_i), | |
| .rst_ni(rst_ni), | |
| .clear_i(trip_o), | |
| .en_i(en_i), | |
| .load_i(1'b0), | |
| .down_i(1'b0), | |
| .delta_i(delta_i), | |
| .d_i('0), | |
| .q_o(q_o), | |
| .overflow_o() | |
| ); | |
| assign last_o = (q_o == bound_i); | |
| assign trip_o = last_o && en_i; | |
| CounterExceedsBound: assert property (@(posedge clk_i) disable iff (( !rst_ni) !== '0) (!(en_i && (q_o + delta_i) > bound_i))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "CounterExceedsBound", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/trip_counter.sv", 49); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module addr_decode #( | |
| parameter int unsigned NoIndices = 32'd0, | |
| parameter int unsigned NoRules = 32'd0, | |
| parameter type addr_t = logic, | |
| parameter type rule_t = logic, | |
| parameter bit Napot = 0, | |
| parameter int unsigned IdxWidth = cf_math_pkg::idx_width(NoIndices), | |
| parameter type idx_t = logic [IdxWidth-1:0] | |
| ) ( | |
| input addr_t addr_i, | |
| input rule_t [NoRules-1:0] addr_map_i, | |
| output idx_t idx_o, | |
| output logic dec_valid_o, | |
| output logic dec_error_o, | |
| input logic en_default_idx_i, | |
| input idx_t default_idx_i | |
| ); | |
| addr_decode_dync #( | |
| .NoRules ( NoRules ), | |
| .addr_t ( addr_t ), | |
| .rule_t ( rule_t ), | |
| .Napot ( Napot ), | |
| .idx_t ( idx_t ) | |
| ) i_addr_decode_dync ( | |
| .addr_i, | |
| .addr_map_i, | |
| .idx_o, | |
| .dec_valid_o, | |
| .dec_error_o, | |
| .en_default_idx_i, | |
| .default_idx_i, | |
| .config_ongoing_i ( 1'b0 ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module addr_decode_napot #( | |
| parameter int unsigned NoIndices = 32'd0, | |
| parameter int unsigned NoRules = 32'd0, | |
| parameter type addr_t = logic, | |
| parameter type rule_t = logic, | |
| parameter int unsigned IdxWidth = cf_math_pkg::idx_width(NoIndices), | |
| parameter type idx_t = logic [IdxWidth-1:0] | |
| ) ( | |
| input addr_t addr_i, | |
| input rule_t [NoRules-1:0] addr_map_i, | |
| output idx_t idx_o, | |
| output logic dec_valid_o, | |
| output logic dec_error_o, | |
| input logic en_default_idx_i, | |
| input idx_t default_idx_i | |
| ); | |
| typedef struct packed { | |
| int unsigned idx; | |
| addr_t start_addr; | |
| addr_t end_addr; | |
| } rule_range_t; | |
| addr_decode_dync #( | |
| .NoIndices ( NoIndices ) , | |
| .NoRules ( NoRules ), | |
| .addr_t ( addr_t ), | |
| .rule_t ( rule_range_t ), | |
| .Napot ( 1 ) | |
| ) i_addr_decode_dync ( | |
| .addr_i, | |
| .addr_map_i, | |
| .idx_o, | |
| .dec_valid_o, | |
| .dec_error_o, | |
| .en_default_idx_i, | |
| .default_idx_i, | |
| .config_ongoing_i ( 1'b0 ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module multiaddr_decode #( | |
| parameter int unsigned NoIndices = 32'd0, | |
| parameter int unsigned NoRules = 32'd0, | |
| parameter type addr_t = logic, | |
| parameter type rule_t = logic | |
| ) ( | |
| input addr_t addr_i, | |
| input addr_t mask_i, | |
| input rule_t [NoRules-1:0] addr_map_i, | |
| output logic [NoIndices-1:0] select_o, | |
| output addr_t [NoIndices-1:0] addr_o, | |
| output addr_t [NoIndices-1:0] mask_o, | |
| output logic dec_valid_o, | |
| output logic dec_error_o | |
| ); | |
| logic [NoRules-1:0] matched_rules; | |
| always_comb begin | |
| matched_rules = '0; | |
| dec_valid_o = 1'b0; | |
| dec_error_o = 1'b1; | |
| select_o = '0; | |
| addr_o = '0; | |
| mask_o = '0; | |
| for (int unsigned i = 0; i < NoRules; i++) begin | |
| automatic int unsigned idx = addr_map_i[i].idx; | |
| automatic addr_t dont_care = mask_i | addr_map_i[i].mask; | |
| automatic addr_t matching_bits = ~(addr_i ^ addr_map_i[i].addr); | |
| automatic logic match = &(dont_care | matching_bits); | |
| if (match) begin | |
| matched_rules[i] = 1'b1; | |
| dec_valid_o = 1'b1; | |
| dec_error_o = 1'b0; | |
| select_o[idx] |= 1'b1; | |
| mask_o[idx] = mask_i & addr_map_i[i].mask; | |
| addr_o[idx] = (~mask_i & addr_i) | (mask_i & addr_map_i[i].addr); | |
| end | |
| end | |
| end | |
| initial begin : proc_check_parameters | |
| norules_0: assume (NoRules > 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "norules_0", $sformatf("At least one rule needed"), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/multiaddr_decode.sv", 127); | |
| end | |
| addr_width_not_equal: assume ($bits(addr_i) == $bits(addr_map_i[0].addr)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "addr_width_not_equal", $sformatf("Input address has %d bits and address map has %d bits.", $bits(addr_i), $bits(addr_map_i[0].addr)), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/multiaddr_decode.sv", 130); | |
| end | |
| end | |
| always_comb begin : proc_check_addr_map | |
| if (!$isunknown(addr_map_i)) begin | |
| for (int unsigned i = 0; i < NoRules; i++) begin | |
| check_idx: assume (addr_map_i[i].idx < NoIndices) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "check_idx", $sformatf("This rule has a IDX that is not allowed!!!\n\ | |
| Violating rule %d.\n\ | |
| Rule> IDX: %h\n\ | |
| Rule> MAX_IDX: %h\n\ | |
| #####################################################", i, addr_map_i[i].idx, (NoIndices-1)), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/multiaddr_decode.sv", 146); | |
| end | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cb_filter #( | |
| parameter int unsigned KHashes = 32'd3, | |
| parameter int unsigned HashWidth = 32'd4, | |
| parameter int unsigned HashRounds = 32'd1, | |
| parameter int unsigned InpWidth = 32'd32, | |
| parameter int unsigned BucketWidth = 32'd4, | |
| parameter cb_filter_pkg::cb_seed_t [KHashes-1:0] Seeds = cb_filter_pkg::EgSeeds | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic [InpWidth-1:0] look_data_i, | |
| output logic look_valid_o, | |
| input logic [InpWidth-1:0] incr_data_i, | |
| input logic incr_valid_i, | |
| input logic [InpWidth-1:0] decr_data_i, | |
| input logic decr_valid_i, | |
| input logic filter_clear_i, | |
| output logic [HashWidth-1:0] filter_usage_o, | |
| output logic filter_full_o, | |
| output logic filter_empty_o, | |
| output logic filter_error_o | |
| ); | |
| localparam int unsigned NoCounters = 2**HashWidth; | |
| logic [NoCounters-1:0] look_ind; | |
| logic [NoCounters-1:0] incr_ind; | |
| logic [NoCounters-1:0] decr_ind; | |
| logic [NoCounters-1:0] bucket_en; | |
| logic [NoCounters-1:0] bucket_down; | |
| logic [NoCounters-1:0] bucket_occupied; | |
| logic [NoCounters-1:0] bucket_overflow; | |
| logic [NoCounters-1:0] bucket_full; | |
| logic [NoCounters-1:0] bucket_empty; | |
| logic [NoCounters-1:0] data_in_bucket; | |
| logic cnt_en; | |
| logic cnt_down; | |
| logic cnt_overflow; | |
| hash_block #( | |
| .NoHashes ( KHashes ), | |
| .InpWidth ( InpWidth ), | |
| .HashWidth ( HashWidth ), | |
| .NoRounds ( HashRounds ), | |
| .Seeds ( Seeds ) | |
| ) i_look_hashes ( | |
| .data_i ( look_data_i ), | |
| .indicator_o ( look_ind ) | |
| ); | |
| assign data_in_bucket = look_ind & bucket_occupied; | |
| assign look_valid_o = (data_in_bucket == look_ind) ? 1'b1 : 1'b0; | |
| hash_block #( | |
| .NoHashes ( KHashes ), | |
| .InpWidth ( InpWidth ), | |
| .HashWidth ( HashWidth ), | |
| .NoRounds ( HashRounds ), | |
| .Seeds ( Seeds ) | |
| ) i_incr_hashes ( | |
| .data_i ( incr_data_i ), | |
| .indicator_o ( incr_ind ) | |
| ); | |
| hash_block #( | |
| .NoHashes ( KHashes ), | |
| .InpWidth ( InpWidth ), | |
| .HashWidth ( HashWidth ), | |
| .NoRounds ( HashRounds ), | |
| .Seeds ( Seeds ) | |
| ) i_decr_hashes ( | |
| .data_i ( decr_data_i ), | |
| .indicator_o ( decr_ind ) | |
| ); | |
| assign bucket_down = decr_valid_i ? decr_ind : '0; | |
| always_comb begin : proc_bucket_control | |
| case ({incr_valid_i, decr_valid_i}) | |
| 2'b00 : bucket_en = '0; | |
| 2'b10 : bucket_en = incr_ind; | |
| 2'b01 : bucket_en = decr_ind; | |
| 2'b11 : bucket_en = incr_ind ^ decr_ind; | |
| default: bucket_en = '0; | |
| endcase | |
| end | |
| for (genvar i = 0; i < NoCounters; i++) begin : gen_buckets | |
| logic [BucketWidth-1:0] bucket_content; | |
| counter #( | |
| .WIDTH( BucketWidth ) | |
| ) i_bucket ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .clear_i ( filter_clear_i ), | |
| .en_i ( bucket_en[i] ), | |
| .load_i ( '0 ), | |
| .down_i ( bucket_down[i] ), | |
| .d_i ( '0 ), | |
| .q_o ( bucket_content ), | |
| .overflow_o ( bucket_overflow[i]) | |
| ); | |
| assign bucket_full[i] = bucket_overflow[i] | (&bucket_content); | |
| assign bucket_occupied[i] = |bucket_content; | |
| assign bucket_empty[i] = ~bucket_occupied[i]; | |
| end | |
| assign cnt_en = incr_valid_i ^ decr_valid_i; | |
| assign cnt_down = decr_valid_i; | |
| counter #( | |
| .WIDTH ( HashWidth ) | |
| ) i_tot_count ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .clear_i ( filter_clear_i ), | |
| .en_i ( cnt_en ), | |
| .load_i ( '0 ), | |
| .down_i ( cnt_down ), | |
| .d_i ( '0 ), | |
| .q_o ( filter_usage_o ), | |
| .overflow_o( cnt_overflow ) | |
| ); | |
| assign filter_full_o = |bucket_full; | |
| assign filter_empty_o = &bucket_empty; | |
| assign filter_error_o = |bucket_overflow | cnt_overflow; | |
| endmodule | |
| module hash_block #( | |
| parameter int unsigned NoHashes = 32'd3, | |
| parameter int unsigned InpWidth = 32'd11, | |
| parameter int unsigned HashWidth = 32'd5, | |
| parameter int unsigned NoRounds = 32'd1, | |
| parameter cb_filter_pkg::cb_seed_t [NoHashes-1:0] Seeds = cb_filter_pkg::EgSeeds | |
| ) ( | |
| input logic [InpWidth-1:0] data_i, | |
| output logic [2**HashWidth-1:0] indicator_o | |
| ); | |
| logic [NoHashes-1:0][2**HashWidth-1:0] hashes; | |
| for (genvar i = 0; i < NoHashes; i++) begin : gen_hashes | |
| sub_per_hash #( | |
| .InpWidth ( InpWidth ), | |
| .HashWidth ( HashWidth ), | |
| .NoRounds ( NoRounds ), | |
| .PermuteKey ( Seeds[i].PermuteSeed ), | |
| .XorKey ( Seeds[i].XorSeed ) | |
| ) i_hash ( | |
| .data_i ( data_i ), | |
| .hash_o ( ), | |
| .hash_onehot_o ( hashes[i] ) | |
| ); | |
| end | |
| always_comb begin : proc_hash_or | |
| indicator_o = '0; | |
| for (int unsigned j = 0; j < NoHashes; j++) begin | |
| indicator_o = indicator_o | hashes[j]; | |
| end | |
| end | |
| initial begin | |
| hash_conf: assume (InpWidth > HashWidth) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "hash_conf", $sformatf("%m:\nA Hash Function reduces the width of the input>\nInpWidth: %s\nOUT_WIDTH: %s", InpWidth, HashWidth), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cb_filter.sv", 243); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cdc_fifo_2phase #( | |
| parameter type T = logic, | |
| parameter int LOG_DEPTH = 3 | |
| )( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input T src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| output T dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| initial begin | |
| log_depth_0: assert (LOG_DEPTH > 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "log_depth_0", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_fifo_2phase.sv", 68); | |
| end | |
| end | |
| localparam int PtrWidth = LOG_DEPTH+1; | |
| typedef logic [PtrWidth-1:0] pointer_t; | |
| typedef logic [LOG_DEPTH-1:0] index_t; | |
| localparam pointer_t PtrFull = (1 << LOG_DEPTH); | |
| localparam pointer_t PtrEmpty = '0; | |
| index_t fifo_widx, fifo_ridx; | |
| logic fifo_write; | |
| T fifo_wdata, fifo_rdata; | |
| T fifo_data_q [2**LOG_DEPTH]; | |
| assign fifo_rdata = fifo_data_q[fifo_ridx]; | |
| for (genvar i = 0; i < 2**LOG_DEPTH; i++) begin : g_word | |
| always_ff @(posedge src_clk_i, negedge src_rst_ni) begin | |
| if (!src_rst_ni) | |
| fifo_data_q[i] <= T'('0); | |
| else if (fifo_write && fifo_widx == i) | |
| fifo_data_q[i] <= fifo_wdata; | |
| end | |
| end | |
| pointer_t src_wptr_q, dst_wptr, src_rptr, dst_rptr_q; | |
| always_ff @(posedge src_clk_i, negedge src_rst_ni) begin | |
| if (!src_rst_ni) | |
| src_wptr_q <= 0; | |
| else if (src_valid_i && src_ready_o) | |
| src_wptr_q <= src_wptr_q + 1; | |
| end | |
| always_ff @(posedge dst_clk_i, negedge dst_rst_ni) begin | |
| if (!dst_rst_ni) | |
| dst_rptr_q <= 0; | |
| else if (dst_valid_o && dst_ready_i) | |
| dst_rptr_q <= dst_rptr_q + 1; | |
| end | |
| assign src_ready_o = ((src_wptr_q ^ src_rptr) != PtrFull); | |
| assign dst_valid_o = ((dst_rptr_q ^ dst_wptr) != PtrEmpty); | |
| cdc_2phase #( .T(pointer_t) ) i_cdc_wptr ( | |
| .src_rst_ni ( src_rst_ni ), | |
| .src_clk_i ( src_clk_i ), | |
| .src_data_i ( src_wptr_q ), | |
| .src_valid_i ( 1'b1 ), | |
| .src_ready_o ( ), | |
| .dst_rst_ni ( dst_rst_ni ), | |
| .dst_clk_i ( dst_clk_i ), | |
| .dst_data_o ( dst_wptr ), | |
| .dst_valid_o ( ), | |
| .dst_ready_i ( 1'b1 ) | |
| ); | |
| cdc_2phase #( .T(pointer_t) ) i_cdc_rptr ( | |
| .src_rst_ni ( dst_rst_ni ), | |
| .src_clk_i ( dst_clk_i ), | |
| .src_data_i ( dst_rptr_q ), | |
| .src_valid_i ( 1'b1 ), | |
| .src_ready_o ( ), | |
| .dst_rst_ni ( src_rst_ni ), | |
| .dst_clk_i ( src_clk_i ), | |
| .dst_data_o ( src_rptr ), | |
| .dst_valid_o ( ), | |
| .dst_ready_i ( 1'b1 ) | |
| ); | |
| assign fifo_widx = src_wptr_q; | |
| assign fifo_wdata = src_data_i; | |
| assign fifo_write = src_valid_i && src_ready_o; | |
| assign fifo_ridx = dst_rptr_q; | |
| assign dst_data_o = fifo_rdata; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module clk_mux_glitch_free #( | |
| parameter int unsigned NUM_INPUTS = 2, | |
| parameter int unsigned NUM_SYNC_STAGES = 2, | |
| parameter bit CLOCK_DURING_RESET = 1'b1, | |
| localparam int unsigned SelWidth = $clog2(NUM_INPUTS) | |
| ) ( | |
| input logic [NUM_INPUTS-1:0] clks_i, | |
| input logic test_clk_i, | |
| input logic test_en_i, | |
| input logic async_rstn_i, | |
| input logic [SelWidth-1:0] async_sel_i, | |
| output logic clk_o | |
| ); | |
| if (NUM_INPUTS<2) | |
| $error("Num inputs must be parametrized to a value >= 2."); | |
| logic [NUM_INPUTS-1:0] s_sel_onehot; | |
| (*dont_touch*) | |
| (*async_reg*) | |
| logic [NUM_INPUTS-1:0][1:0] glitch_filter_d, glitch_filter_q; | |
| logic [NUM_INPUTS-1:0] s_gate_enable_unfiltered_async; | |
| logic [NUM_INPUTS-1:0] s_glitch_filter_output_async; | |
| logic [NUM_INPUTS-1:0] s_gate_enable_sync; | |
| logic [NUM_INPUTS-1:0] s_gate_enable; | |
| logic [NUM_INPUTS-1:0] clock_has_been_disabled_q; | |
| logic [NUM_INPUTS-1:0] s_gated_clock; | |
| logic s_output_clock; | |
| logic [NUM_INPUTS-1:0] s_reset_synced; | |
| logic [NUM_INPUTS-1:0] async_reset_bypass_active_q; | |
| always_comb begin | |
| s_sel_onehot = '0; | |
| s_sel_onehot[async_sel_i] = 1'b1; | |
| end | |
| for (genvar i = 0; i < NUM_INPUTS; i++) begin : gen_input_stages | |
| rstgen i_rstgen( | |
| .clk_i ( clks_i[i] ), | |
| .rst_ni ( async_rstn_i ), | |
| .test_mode_i ( test_en_i ), | |
| .rst_no ( s_reset_synced[i] ), | |
| .init_no ( ) | |
| ); | |
| always_comb begin | |
| s_gate_enable_unfiltered_async[i] = 1'b1; | |
| for (int j = 0; j < NUM_INPUTS; j++) begin | |
| if (i==j) begin | |
| s_gate_enable_unfiltered_async[i] &= s_sel_onehot[j]; | |
| end else begin | |
| s_gate_enable_unfiltered_async[i] &= clock_has_been_disabled_q[j]; | |
| end | |
| end | |
| end | |
| assign glitch_filter_d[i][0] = s_gate_enable_unfiltered_async[i]; | |
| assign glitch_filter_d[i][1] = glitch_filter_q[i][0]; | |
| always_ff @(posedge clks_i[i], negedge s_reset_synced[i]) begin | |
| if (!s_reset_synced[i]) begin | |
| glitch_filter_q[i] <= '0; | |
| end else begin | |
| glitch_filter_q[i] <= glitch_filter_d[i]; | |
| end | |
| end | |
| assign s_glitch_filter_output_async[i] = glitch_filter_q[i][1] & | |
| glitch_filter_q[i][0] & | |
| s_gate_enable_unfiltered_async[i]; | |
| sync #(.STAGES(NUM_SYNC_STAGES)) i_sync_en( | |
| .clk_i ( clks_i[i] ), | |
| .rst_ni ( s_reset_synced[i] ), | |
| .serial_i ( s_glitch_filter_output_async[i] ), | |
| .serial_o ( s_gate_enable_sync[i] ) | |
| ); | |
| if (CLOCK_DURING_RESET) begin : gen_async_reset_clock_bypass_logic | |
| always_ff @(posedge clks_i[i], negedge s_reset_synced[i]) begin | |
| if (!s_reset_synced[i]) begin | |
| async_reset_bypass_active_q[i] <= 1'b1; | |
| end else begin | |
| async_reset_bypass_active_q[i] <= 1'b0; | |
| end | |
| end | |
| assign s_gate_enable[i] = async_reset_bypass_active_q[i]? | |
| s_gate_enable_unfiltered_async[i] | |
| : s_gate_enable_sync[i]; | |
| end else begin : gen_no_async_reset_bypass_logic | |
| assign s_gate_enable[i] = s_gate_enable_sync[i]; | |
| end | |
| tc_clk_gating #( | |
| .IS_FUNCTIONAL(1'b1) | |
| ) i_clk_gate ( | |
| .clk_i ( clks_i[i] ), | |
| .en_i ( s_gate_enable[i] ), | |
| .test_en_i ( 1'b0 ), | |
| .clk_o ( s_gated_clock[i] ) | |
| ); | |
| always_ff @(posedge clks_i[i], negedge s_reset_synced[i]) begin | |
| if (!s_reset_synced[i]) begin | |
| clock_has_been_disabled_q[i] <= 1'b1; | |
| end else begin | |
| clock_has_been_disabled_q[i] <= ~s_gate_enable[i]; | |
| end | |
| end | |
| end | |
| clk_or_tree #(NUM_INPUTS) i_clk_or_tree ( | |
| .clks_i(s_gated_clock), | |
| .clk_o(s_output_clock) | |
| ); | |
| tc_clk_mux2 i_test_clk_mux( | |
| .clk0_i(s_output_clock), | |
| .clk1_i(test_clk_i), | |
| .clk_sel_i(test_en_i), | |
| .clk_o | |
| ); | |
| endmodule | |
| module clk_or_tree #( | |
| parameter int unsigned NUM_INPUTS | |
| ) ( | |
| input logic [NUM_INPUTS-1:0] clks_i, | |
| output logic clk_o | |
| ); | |
| if (NUM_INPUTS < 1) begin : gen_error | |
| $error("Cannot parametrize clk_or with less then 1 input but was %0d", NUM_INPUTS); | |
| end else if (NUM_INPUTS == 1) begin : gen_leaf | |
| assign clk_o = clks_i[0]; | |
| end else if (NUM_INPUTS == 2) begin : gen_leaf | |
| tc_clk_or2 i_clk_or2 ( | |
| .clk0_i(clks_i[0]), | |
| .clk1_i(clks_i[1]), | |
| .clk_o | |
| ); | |
| end else begin : gen_recursive | |
| logic branch_a, branch_b; | |
| clk_or_tree #(NUM_INPUTS/2) i_or_branch_a ( | |
| .clks_i(clks_i[0+:NUM_INPUTS/2]), | |
| .clk_o(branch_a) | |
| ); | |
| clk_or_tree #(NUM_INPUTS/2 + NUM_INPUTS%2) i_or_branch_b ( | |
| .clks_i(clks_i[NUM_INPUTS-1:NUM_INPUTS/2]), | |
| .clk_o(branch_b) | |
| ); | |
| tc_clk_or2 i_clk_or2 ( | |
| .clk0_i(branch_a), | |
| .clk1_i(branch_b), | |
| .clk_o | |
| ); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module counter #( | |
| parameter int unsigned WIDTH = 4, | |
| parameter bit STICKY_OVERFLOW = 1'b0 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic clear_i, | |
| input logic en_i, | |
| input logic load_i, | |
| input logic down_i, | |
| input logic [WIDTH-1:0] d_i, | |
| output logic [WIDTH-1:0] q_o, | |
| output logic overflow_o | |
| ); | |
| delta_counter #( | |
| .WIDTH (WIDTH), | |
| .STICKY_OVERFLOW (STICKY_OVERFLOW) | |
| ) i_counter ( | |
| .clk_i, | |
| .rst_ni, | |
| .clear_i, | |
| .en_i, | |
| .load_i, | |
| .down_i, | |
| .delta_i({{WIDTH-1{1'b0}}, 1'b1}), | |
| .d_i, | |
| .q_o, | |
| .overflow_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module ecc_decode import ecc_pkg::*; #( | |
| parameter int unsigned DataWidth = 64, | |
| parameter type data_t = logic [DataWidth-1:0], | |
| parameter type parity_t = logic [get_parity_width(DataWidth)-1:0], | |
| parameter type code_word_t = logic [get_cw_width(DataWidth)-1:0], | |
| parameter type encoded_data_t = struct packed { | |
| logic parity; | |
| code_word_t code_word; | |
| } | |
| ) ( | |
| input encoded_data_t data_i, | |
| output data_t data_o, | |
| output parity_t syndrome_o, | |
| output logic single_error_o, | |
| output logic parity_error_o, | |
| output logic double_error_o | |
| ); | |
| logic parity; | |
| data_t data_wo_parity; | |
| parity_t syndrome; | |
| logic syndrome_not_zero; | |
| code_word_t correct_data; | |
| assign parity = data_i.parity ^ (^data_i.code_word); | |
| always_comb begin : calculate_syndrome | |
| syndrome = 0; | |
| for (int unsigned i = 0; i < unsigned'($bits(parity_t)); i++) begin | |
| for (int unsigned j = 0; j < unsigned'($bits(code_word_t)); j++) begin | |
| if (|(unsigned'(2**i) & (j + 1))) syndrome[i] = syndrome[i] ^ data_i.code_word[j]; | |
| end | |
| end | |
| end | |
| assign syndrome_not_zero = |syndrome; | |
| always_comb begin | |
| correct_data = data_i.code_word; | |
| if (syndrome_not_zero) begin | |
| correct_data[syndrome - 1] = ~data_i.code_word[syndrome - 1]; | |
| end | |
| end | |
| assign single_error_o = parity & syndrome_not_zero; | |
| assign parity_error_o = parity & ~syndrome_not_zero; | |
| assign double_error_o = ~parity & syndrome_not_zero; | |
| always_comb begin | |
| automatic int unsigned idx; | |
| data_wo_parity = '0; | |
| idx = 0; | |
| for (int unsigned i = 1; i < unsigned'($bits(code_word_t)) + 1; i++) begin | |
| if (unsigned'(2**$clog2(i)) != i) begin | |
| data_wo_parity[idx] = correct_data[i - 1]; | |
| idx++; | |
| end | |
| end | |
| end | |
| assign data_o = data_wo_parity; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module ecc_encode import ecc_pkg::*; #( | |
| parameter int unsigned DataWidth = 64, | |
| parameter type data_t = logic [DataWidth-1:0], | |
| parameter type parity_t = logic [get_parity_width(DataWidth)-1:0], | |
| parameter type code_word_t = logic [get_cw_width(DataWidth)-1:0], | |
| parameter type encoded_data_t = struct packed { | |
| logic parity; | |
| code_word_t code_word; | |
| } | |
| ) ( | |
| input data_t data_i, | |
| output encoded_data_t data_o | |
| ); | |
| parity_t parity_code_word; | |
| code_word_t data, codeword; | |
| always_comb begin : expand_data | |
| automatic int unsigned idx; | |
| data = '0; | |
| idx = 0; | |
| for (int unsigned i = 1; i < unsigned'($bits(code_word_t)) + 1; i++) begin | |
| if (unsigned'(2**$clog2(i)) != i) begin | |
| data[i - 1] = data_i[idx]; | |
| idx++; | |
| end | |
| end | |
| end | |
| always_comb begin : calculate_syndrome | |
| parity_code_word = 0; | |
| for (int unsigned i = 0; i < unsigned'($bits(parity_t)); i++) begin | |
| for (int unsigned j = 1; j < unsigned'($bits(code_word_t)) + 1; j++) begin | |
| if (|(unsigned'(2**i) & j)) parity_code_word[i] = parity_code_word[i] ^ data[j - 1]; | |
| end | |
| end | |
| end | |
| always_comb begin : generate_codeword | |
| codeword = data; | |
| for (int unsigned i = 0; i < unsigned'($bits(parity_t)); i++) begin | |
| codeword[2**i-1] = parity_code_word[i]; | |
| end | |
| end | |
| assign data_o.code_word = codeword; | |
| assign data_o.parity = ^codeword; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module edge_detect ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic d_i, | |
| output logic re_o, | |
| output logic fe_o | |
| ); | |
| sync_wedge i_sync_wedge ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .en_i ( 1'b1 ), | |
| .serial_i ( d_i ), | |
| .r_edge_o ( re_o ), | |
| .f_edge_o ( fe_o ), | |
| .serial_o ( ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module lzc #( | |
| parameter int unsigned WIDTH = 2, | |
| parameter bit MODE = 1'b0, | |
| parameter int unsigned CNT_WIDTH = cf_math_pkg::idx_width(WIDTH) | |
| ) ( | |
| input logic [WIDTH-1:0] in_i, | |
| output logic [CNT_WIDTH-1:0] cnt_o, | |
| output logic empty_o | |
| ); | |
| initial begin | |
| width_0: assert (WIDTH > 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "width_0", "input must be at least one bit wide", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/lzc.sv", 36); | |
| end | |
| end | |
| if (WIDTH <= 1) begin : gen_degenerate_lzc | |
| assign cnt_o[0] = !in_i[0]; | |
| assign empty_o = !in_i[0]; | |
| end else begin : gen_lzc | |
| localparam int unsigned NumLevels = $clog2(WIDTH); | |
| logic [WIDTH-1:0][NumLevels-1:0] index_lut; | |
| logic [2**NumLevels-1:0] sel_nodes /*verilator split_var*/; | |
| logic [2**NumLevels-1:0][NumLevels-1:0] index_nodes /*verilator split_var*/; | |
| logic [WIDTH-1:0] in_tmp; | |
| if (MODE) begin : g_flip | |
| always_comb begin : flip_vector | |
| for (int unsigned i = 0; i < WIDTH; i++) begin | |
| in_tmp[i] = in_i[WIDTH-1-i]; | |
| end | |
| end | |
| end else begin : g_no_flip | |
| assign in_tmp = in_i; | |
| end | |
| for (genvar j = 0; unsigned'(j) < WIDTH; j++) begin : g_index_lut | |
| assign index_lut[j] = (NumLevels)'(unsigned'(j)); | |
| end | |
| for (genvar level = 0; unsigned'(level) < NumLevels; level++) begin : g_levels | |
| if (unsigned'(level) == NumLevels - 1) begin : g_last_level | |
| for (genvar k = 0; k < 2 ** level; k++) begin : g_level | |
| if (unsigned'(k) * 2 < WIDTH - 1) begin : g_reduce | |
| assign sel_nodes[2 ** level - 1 + k] = in_tmp[k * 2] | in_tmp[k * 2 + 1]; | |
| assign index_nodes[2 ** level - 1 + k] = (in_tmp[k * 2] == 1'b1) | |
| ? index_lut[k * 2] : | |
| index_lut[k * 2 + 1]; | |
| end | |
| if (unsigned'(k) * 2 == WIDTH - 1) begin : g_base | |
| assign sel_nodes[2 ** level - 1 + k] = in_tmp[k * 2]; | |
| assign index_nodes[2 ** level - 1 + k] = index_lut[k * 2]; | |
| end | |
| if (unsigned'(k) * 2 > WIDTH - 1) begin : g_out_of_range | |
| assign sel_nodes[2 ** level - 1 + k] = 1'b0; | |
| assign index_nodes[2 ** level - 1 + k] = '0; | |
| end | |
| end | |
| end else begin : g_not_last_level | |
| for (genvar l = 0; l < 2 ** level; l++) begin : g_level | |
| assign sel_nodes[2 ** level - 1 + l] = | |
| sel_nodes[2 ** (level + 1) - 1 + l * 2] | sel_nodes[2 ** (level + 1) - 1 + l * 2 + 1]; | |
| assign index_nodes[2 ** level - 1 + l] = (sel_nodes[2 ** (level + 1) - 1 + l * 2] == 1'b1) | |
| ? index_nodes[2 ** (level + 1) - 1 + l * 2] : | |
| index_nodes[2 ** (level + 1) - 1 + l * 2 + 1]; | |
| end | |
| end | |
| end | |
| assign cnt_o = NumLevels > unsigned'(0) ? index_nodes[0] : {($clog2(WIDTH)) {1'b0}}; | |
| assign empty_o = NumLevels > unsigned'(0) ? ~sel_nodes[0] : ~(|in_i); | |
| end : gen_lzc | |
| endmodule : lzc | |
| `begin_keywords "1800-2023" | |
| module max_counter #( | |
| parameter int unsigned WIDTH = 4 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic clear_i, | |
| input logic clear_max_i, | |
| input logic en_i, | |
| input logic load_i, | |
| input logic down_i, | |
| input logic [WIDTH-1:0] delta_i, | |
| input logic [WIDTH-1:0] d_i, | |
| output logic [WIDTH-1:0] q_o, | |
| output logic [WIDTH-1:0] max_o, | |
| output logic overflow_o, | |
| output logic overflow_max_o | |
| ); | |
| logic [WIDTH-1:0] max_d, max_q; | |
| logic overflow_max_d, overflow_max_q; | |
| delta_counter #( | |
| .WIDTH (WIDTH), | |
| .STICKY_OVERFLOW (1'b1) | |
| ) i_counter ( | |
| .clk_i, | |
| .rst_ni, | |
| .clear_i, | |
| .en_i, | |
| .load_i, | |
| .down_i, | |
| .delta_i, | |
| .d_i, | |
| .q_o, | |
| .overflow_o | |
| ); | |
| always_comb begin | |
| max_d = max_q; | |
| max_o = max_q; | |
| overflow_max_d = overflow_max_q; | |
| if (clear_max_i) begin | |
| max_d = '0; | |
| overflow_max_d = 1'b0; | |
| end else if (q_o > max_q) begin | |
| max_d = q_o; | |
| max_o = q_o; | |
| if (overflow_o) begin | |
| overflow_max_d = 1'b1; | |
| end | |
| end | |
| end | |
| assign overflow_max_o = overflow_max_q; | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| max_q <= '0; | |
| overflow_max_q <= 1'b0; | |
| end else begin | |
| max_q <= max_d; | |
| overflow_max_q <= overflow_max_d; | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module rstgen ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_mode_i, | |
| output logic rst_no, | |
| output logic init_no | |
| ); | |
| rstgen_bypass i_rstgen_bypass ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .rst_test_mode_ni ( rst_ni ), | |
| .test_mode_i ( test_mode_i ), | |
| .rst_no ( rst_no ), | |
| .init_no ( init_no ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module spill_register #( | |
| parameter type T = logic, | |
| parameter bit Bypass = 1'b0 | |
| ) ( | |
| input logic clk_i , | |
| input logic rst_ni , | |
| input logic valid_i , | |
| output logic ready_o , | |
| input T data_i , | |
| output logic valid_o , | |
| input logic ready_i , | |
| output T data_o | |
| ); | |
| spill_register_flushable #( | |
| .T(T), | |
| .Bypass(Bypass) | |
| ) spill_register_flushable_i ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i, | |
| .flush_i(1'b0), | |
| .ready_o, | |
| .data_i, | |
| .valid_o, | |
| .ready_i, | |
| .data_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_delay #( | |
| parameter bit StallRandom = 0, | |
| parameter int FixedDelay = 1, | |
| parameter type payload_t = logic, | |
| parameter logic [15:0] Seed = '0 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input payload_t payload_i, | |
| output logic ready_o, | |
| input logic valid_i, | |
| output payload_t payload_o, | |
| input logic ready_i, | |
| output logic valid_o | |
| ); | |
| if (FixedDelay == 0 && !StallRandom) begin : gen_pass_through | |
| assign ready_o = ready_i; | |
| assign valid_o = valid_i; | |
| assign payload_o = payload_i; | |
| end else begin : gen_delay | |
| localparam int unsigned CounterBits = 32; | |
| typedef enum logic [1:0] { | |
| Idle, Valid, Ready | |
| } state_e; | |
| state_e state_d, state_q; | |
| logic load; | |
| logic [CounterBits-1:0] count_out; | |
| logic en; | |
| logic [CounterBits-1:0] counter_load; | |
| assign payload_o = payload_i; | |
| always_comb begin | |
| state_d = state_q; | |
| valid_o = 1'b0; | |
| ready_o = 1'b0; | |
| load = 1'b0; | |
| en = 1'b0; | |
| unique case (state_q) | |
| Idle: begin | |
| if (valid_i) begin | |
| load = 1'b1; | |
| state_d = Valid; | |
| if (FixedDelay == 1 || (StallRandom && counter_load == 1)) begin | |
| state_d = Ready; | |
| end | |
| if (StallRandom && counter_load == 0) begin | |
| valid_o = 1'b1; | |
| ready_o = ready_i; | |
| if (ready_i) state_d = Idle; | |
| else state_d = Ready; | |
| end | |
| end | |
| end | |
| Valid: begin | |
| en = 1'b1; | |
| if (count_out == 0) begin | |
| state_d = Ready; | |
| end | |
| end | |
| Ready: begin | |
| valid_o = 1'b1; | |
| ready_o = ready_i; | |
| if (ready_i) state_d = Idle; | |
| end | |
| default : ; | |
| endcase | |
| end | |
| if (StallRandom) begin : gen_random_stall | |
| lfsr_16bit #( | |
| .WIDTH ( 16 ), | |
| .SEED ( Seed ) | |
| ) i_lfsr_16bit ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .en_i ( load ), | |
| .refill_way_oh ( ), | |
| .refill_way_bin ( counter_load ) | |
| ); | |
| end else begin : gen_fixed_delay | |
| assign counter_load = FixedDelay; | |
| end | |
| counter #( | |
| .WIDTH ( CounterBits ) | |
| ) i_counter ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .clear_i ( 1'b0 ), | |
| .en_i ( en ), | |
| .load_i ( load ), | |
| .down_i ( 1'b1 ), | |
| .d_i ( counter_load ), | |
| .q_o ( count_out ), | |
| .overflow_o ( ) | |
| ); | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (~rst_ni) begin | |
| state_q <= Idle; | |
| end else begin | |
| state_q <= state_d; | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_fifo #( | |
| parameter bit FALL_THROUGH = 1'b0, | |
| parameter int unsigned DATA_WIDTH = 32, | |
| parameter int unsigned DEPTH = 8, | |
| parameter type T = logic [DATA_WIDTH-1:0], | |
| parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input logic testmode_i, | |
| output logic [ADDR_DEPTH-1:0] usage_o, | |
| input T data_i, | |
| input logic valid_i, | |
| output logic ready_o, | |
| output T data_o, | |
| output logic valid_o, | |
| input logic ready_i | |
| ); | |
| logic push, pop; | |
| logic empty, full; | |
| assign push = valid_i & ~full; | |
| assign pop = ready_i & ~empty; | |
| assign ready_o = ~full; | |
| assign valid_o = ~empty; | |
| fifo_v3 #( | |
| .FALL_THROUGH (FALL_THROUGH), | |
| .DATA_WIDTH (DATA_WIDTH), | |
| .DEPTH (DEPTH), | |
| .dtype(T) | |
| ) fifo_i ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .testmode_i, | |
| .full_o (full), | |
| .empty_o (empty), | |
| .usage_o, | |
| .data_i, | |
| .push_i (push), | |
| .data_o, | |
| .pop_i (pop) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_fork_dynamic #( | |
| parameter int unsigned N_OUP = 32'd0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic valid_i, | |
| output logic ready_o, | |
| input logic [N_OUP-1:0] sel_i, | |
| input logic sel_valid_i, | |
| output logic sel_ready_o, | |
| output logic [N_OUP-1:0] valid_o, | |
| input logic [N_OUP-1:0] ready_i | |
| ); | |
| logic int_inp_valid, int_inp_ready; | |
| logic [N_OUP-1:0] int_oup_valid, int_oup_ready; | |
| for (genvar i = 0; i < N_OUP; i++) begin : gen_oups | |
| always_comb begin | |
| valid_o[i] = 1'b0; | |
| int_oup_ready[i] = 1'b0; | |
| if (sel_valid_i) begin | |
| if (sel_i[i]) begin | |
| valid_o[i] = int_oup_valid[i]; | |
| int_oup_ready[i] = ready_i[i]; | |
| end else begin | |
| int_oup_ready[i] = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| always_comb begin | |
| int_inp_valid = 1'b0; | |
| ready_o = 1'b0; | |
| sel_ready_o = 1'b0; | |
| if (sel_valid_i) begin | |
| int_inp_valid = valid_i; | |
| ready_o = int_inp_ready; | |
| sel_ready_o = int_inp_ready; | |
| end | |
| end | |
| stream_fork #( | |
| .N_OUP ( N_OUP ) | |
| ) i_fork ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( int_inp_valid ), | |
| .ready_o ( int_inp_ready ), | |
| .valid_o ( int_oup_valid ), | |
| .ready_i ( int_oup_ready ) | |
| ); | |
| initial begin | |
| n_oup_0: assert (N_OUP >= 1) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "n_oup_0", "N_OUP must be at least 1!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_fork_dynamic.sv", 91); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_join #( | |
| parameter int unsigned N_INP = 32'd0 | |
| ) ( | |
| input logic [N_INP-1:0] inp_valid_i, | |
| output logic [N_INP-1:0] inp_ready_o, | |
| output logic oup_valid_o, | |
| input logic oup_ready_i | |
| ); | |
| stream_join_dynamic #( | |
| .N_INP(N_INP) | |
| ) i_stream_join_dynamic ( | |
| .inp_valid_i(inp_valid_i), | |
| .inp_ready_o(inp_ready_o), | |
| .sel_i ({N_INP{1'b1}}), | |
| .oup_valid_o(oup_valid_o), | |
| .oup_ready_i(oup_ready_i) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cdc_reset_ctrlr | |
| import cdc_reset_ctrlr_pkg::*; | |
| #( | |
| parameter int unsigned SYNC_STAGES = 2, | |
| parameter logic CLEAR_ON_ASYNC_RESET = 1'b1 | |
| )( | |
| input logic a_clk_i, | |
| input logic a_rst_ni, | |
| input logic a_clear_i, | |
| output logic a_clear_o, | |
| input logic a_clear_ack_i, | |
| output logic a_isolate_o, | |
| input logic a_isolate_ack_i, | |
| input logic b_clk_i, | |
| input logic b_rst_ni, | |
| input logic b_clear_i, | |
| output logic b_clear_o, | |
| input logic b_clear_ack_i, | |
| output logic b_isolate_o, | |
| input logic b_isolate_ack_i | |
| ); | |
| (* dont_touch = "true" *) | |
| logic async_a2b_req, async_b2a_ack; | |
| (* dont_touch = "true" *) | |
| clear_seq_phase_e async_a2b_next_phase; | |
| (* dont_touch = "true" *) | |
| logic async_b2a_req, async_a2b_ack; | |
| (* dont_touch = "true" *) | |
| clear_seq_phase_e async_b2a_next_phase; | |
| cdc_reset_ctrlr_half #( | |
| .SYNC_STAGES ( SYNC_STAGES ), | |
| .CLEAR_ON_ASYNC_RESET ( CLEAR_ON_ASYNC_RESET ) | |
| ) i_cdc_reset_ctrlr_half_a ( | |
| .clk_i ( a_clk_i ), | |
| .rst_ni ( a_rst_ni ), | |
| .clear_i ( a_clear_i ), | |
| .clear_o ( a_clear_o ), | |
| .clear_ack_i ( a_clear_ack_i ), | |
| .isolate_o ( a_isolate_o ), | |
| .isolate_ack_i ( a_isolate_ack_i ), | |
| (* async *) .async_next_phase_o ( async_a2b_next_phase ), | |
| (* async *) .async_req_o ( async_a2b_req ), | |
| (* async *) .async_ack_i ( async_b2a_ack ), | |
| (* async *) .async_next_phase_i ( async_b2a_next_phase ), | |
| (* async *) .async_req_i ( async_b2a_req ), | |
| (* async *) .async_ack_o ( async_a2b_ack ) | |
| ); | |
| cdc_reset_ctrlr_half #( | |
| .SYNC_STAGES ( SYNC_STAGES ), | |
| .CLEAR_ON_ASYNC_RESET ( CLEAR_ON_ASYNC_RESET ) | |
| ) i_cdc_reset_ctrlr_half_b ( | |
| .clk_i ( b_clk_i ), | |
| .rst_ni ( b_rst_ni ), | |
| .clear_i ( b_clear_i ), | |
| .clear_o ( b_clear_o ), | |
| .clear_ack_i ( b_clear_ack_i ), | |
| .isolate_o ( b_isolate_o ), | |
| .isolate_ack_i ( b_isolate_ack_i ), | |
| (* async *) .async_next_phase_o ( async_b2a_next_phase ), | |
| (* async *) .async_req_o ( async_b2a_req ), | |
| (* async *) .async_ack_i ( async_a2b_ack ), | |
| (* async *) .async_next_phase_i ( async_a2b_next_phase ), | |
| (* async *) .async_req_i ( async_a2b_req ), | |
| (* async *) .async_ack_o ( async_b2a_ack ) | |
| ); | |
| endmodule | |
| module cdc_reset_ctrlr_half | |
| import cdc_reset_ctrlr_pkg::*; | |
| #( | |
| parameter int unsigned SYNC_STAGES = 2, | |
| parameter logic CLEAR_ON_ASYNC_RESET = 1'b1 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic clear_i, | |
| output logic isolate_o, | |
| input logic isolate_ack_i, | |
| output logic clear_o, | |
| input logic clear_ack_i, | |
| output clear_seq_phase_e async_next_phase_o, | |
| output logic async_req_o, | |
| input logic async_ack_i, | |
| input clear_seq_phase_e async_next_phase_i, | |
| input logic async_req_i, | |
| output logic async_ack_o | |
| ); | |
| typedef enum logic[3:0] { | |
| IDLE, | |
| ISOLATE, | |
| WAIT_ISOLATE_PHASE_ACK, | |
| WAIT_ISOLATE_ACK, | |
| CLEAR, | |
| WAIT_CLEAR_PHASE_ACK, | |
| WAIT_CLEAR_ACK, | |
| POST_CLEAR, | |
| FINISHED | |
| } initiator_state_e; | |
| initiator_state_e initiator_state_d, initiator_state_q; | |
| clear_seq_phase_e initiator_clear_seq_phase; | |
| logic initiator_phase_transition_req; | |
| logic initiator_phase_transition_ack; | |
| logic initiator_isolate_out; | |
| logic initiator_clear_out; | |
| always_comb begin | |
| initiator_state_d = initiator_state_q; | |
| initiator_phase_transition_req = 1'b0; | |
| initiator_isolate_out = 1'b0; | |
| initiator_clear_out = 1'b0; | |
| initiator_clear_seq_phase = CLEAR_PHASE_IDLE; | |
| case (initiator_state_q) | |
| IDLE: begin | |
| if (clear_i) begin | |
| initiator_state_d = ISOLATE; | |
| end | |
| end | |
| ISOLATE: begin | |
| initiator_phase_transition_req = 1'b1; | |
| initiator_clear_seq_phase = CLEAR_PHASE_ISOLATE; | |
| initiator_isolate_out = 1'b1; | |
| initiator_clear_out = 1'b0; | |
| if (initiator_phase_transition_ack && isolate_ack_i) begin | |
| initiator_state_d = CLEAR; | |
| end else if (initiator_phase_transition_ack) begin | |
| initiator_state_d = WAIT_ISOLATE_ACK; | |
| end else if (isolate_ack_i) begin | |
| initiator_state_d = WAIT_ISOLATE_PHASE_ACK; | |
| end | |
| end | |
| WAIT_ISOLATE_ACK: begin | |
| initiator_isolate_out = 1'b1; | |
| initiator_clear_out = 1'b0; | |
| initiator_clear_seq_phase = CLEAR_PHASE_ISOLATE; | |
| if (isolate_ack_i) begin | |
| initiator_state_d = CLEAR; | |
| end | |
| end | |
| WAIT_ISOLATE_PHASE_ACK: begin | |
| initiator_phase_transition_req = 1'b1; | |
| initiator_clear_seq_phase = CLEAR_PHASE_ISOLATE; | |
| initiator_isolate_out = 1'b1; | |
| initiator_clear_out = 1'b0; | |
| if (initiator_phase_transition_ack) begin | |
| initiator_state_d = CLEAR; | |
| end | |
| end | |
| CLEAR: begin | |
| initiator_isolate_out = 1'b1; | |
| initiator_clear_out = 1'b1; | |
| initiator_phase_transition_req = 1'b1; | |
| initiator_clear_seq_phase = CLEAR_PHASE_CLEAR; | |
| if (initiator_phase_transition_ack && clear_ack_i) begin | |
| initiator_state_d = POST_CLEAR; | |
| end else if (initiator_phase_transition_ack) begin | |
| initiator_state_d = WAIT_CLEAR_ACK; | |
| end else if (clear_ack_i) begin | |
| initiator_state_d = WAIT_CLEAR_PHASE_ACK; | |
| end | |
| end | |
| WAIT_CLEAR_ACK: begin | |
| initiator_isolate_out = 1'b1; | |
| initiator_clear_out = 1'b1; | |
| initiator_clear_seq_phase = CLEAR_PHASE_CLEAR; | |
| if (clear_ack_i) begin | |
| initiator_state_d = POST_CLEAR; | |
| end | |
| end | |
| WAIT_CLEAR_PHASE_ACK: begin | |
| initiator_phase_transition_req = 1'b1; | |
| initiator_clear_seq_phase = CLEAR_PHASE_CLEAR; | |
| initiator_isolate_out = 1'b1; | |
| initiator_clear_out = 1'b1; | |
| if (initiator_phase_transition_ack) begin | |
| initiator_state_d = POST_CLEAR; | |
| end | |
| end | |
| POST_CLEAR: begin | |
| initiator_isolate_out = 1'b1; | |
| initiator_clear_out = 1'b0; | |
| initiator_phase_transition_req = 1'b1; | |
| initiator_clear_seq_phase = CLEAR_PHASE_POST_CLEAR; | |
| if (initiator_phase_transition_ack) begin | |
| initiator_state_d = FINISHED; | |
| end | |
| end | |
| FINISHED: begin | |
| initiator_isolate_out = 1'b1; | |
| initiator_clear_out = 1'b0; | |
| initiator_phase_transition_req = 1'b1; | |
| initiator_clear_seq_phase = CLEAR_PHASE_IDLE; | |
| if (initiator_phase_transition_ack) begin | |
| initiator_state_d = IDLE; | |
| end | |
| end | |
| default: begin | |
| initiator_state_d = ISOLATE; | |
| end | |
| endcase | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| if (CLEAR_ON_ASYNC_RESET) begin | |
| initiator_state_q <= ISOLATE; | |
| end else begin | |
| initiator_state_q <= IDLE; | |
| end | |
| end else begin | |
| initiator_state_q <= initiator_state_d; | |
| end | |
| end | |
| cdc_4phase_src #( | |
| .T(clear_seq_phase_e), | |
| .SYNC_STAGES(2), | |
| .DECOUPLED(0), | |
| .SEND_RESET_MSG(CLEAR_ON_ASYNC_RESET), | |
| .RESET_MSG(CLEAR_PHASE_ISOLATE) | |
| ) i_state_transition_cdc_src( | |
| .clk_i, | |
| .rst_ni, | |
| .data_i(initiator_clear_seq_phase), | |
| .valid_i(initiator_phase_transition_req), | |
| .ready_o(initiator_phase_transition_ack), | |
| .async_req_o, | |
| .async_ack_i, | |
| .async_data_o(async_next_phase_o) | |
| ); | |
| clear_seq_phase_e receiver_phase_q; | |
| clear_seq_phase_e receiver_next_phase; | |
| logic receiver_phase_req, receiver_phase_ack; | |
| logic receiver_isolate_out; | |
| logic receiver_clear_out; | |
| cdc_4phase_dst #( | |
| .T(clear_seq_phase_e), | |
| .SYNC_STAGES(2), | |
| .DECOUPLED(0) | |
| ) i_state_transition_cdc_dst( | |
| .clk_i, | |
| .rst_ni, | |
| .data_o(receiver_next_phase), | |
| .valid_o(receiver_phase_req), | |
| .ready_i(receiver_phase_ack), | |
| .async_req_i, | |
| .async_ack_o, | |
| .async_data_i(async_next_phase_i) | |
| ); | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| receiver_phase_q <= CLEAR_PHASE_IDLE; | |
| end else if (receiver_phase_req && receiver_phase_ack) begin | |
| receiver_phase_q <= receiver_next_phase; | |
| end | |
| end | |
| always_comb begin | |
| receiver_isolate_out = 1'b0; | |
| receiver_clear_out = 1'b0; | |
| receiver_phase_ack = 1'b0; | |
| if (receiver_phase_req) begin | |
| case (receiver_next_phase) | |
| CLEAR_PHASE_IDLE: begin | |
| receiver_clear_out = 1'b0; | |
| receiver_isolate_out = 1'b0; | |
| receiver_phase_ack = 1'b1; | |
| end | |
| CLEAR_PHASE_ISOLATE: begin | |
| receiver_clear_out = 1'b0; | |
| receiver_isolate_out = 1'b1; | |
| receiver_phase_ack = isolate_ack_i; | |
| end | |
| CLEAR_PHASE_CLEAR: begin | |
| receiver_clear_out = 1'b1; | |
| receiver_isolate_out = 1'b1; | |
| receiver_phase_ack = clear_ack_i; | |
| end | |
| CLEAR_PHASE_POST_CLEAR: begin | |
| receiver_clear_out = 1'b0; | |
| receiver_isolate_out = 1'b1; | |
| receiver_phase_ack = 1'b1; | |
| end | |
| default: begin | |
| receiver_clear_out = 1'b0; | |
| receiver_isolate_out = 1'b0; | |
| receiver_phase_ack = 1'b0; | |
| end | |
| endcase | |
| end else begin | |
| case (receiver_phase_q) | |
| CLEAR_PHASE_IDLE: begin | |
| receiver_clear_out = 1'b0; | |
| receiver_isolate_out = 1'b0; | |
| end | |
| CLEAR_PHASE_ISOLATE: begin | |
| receiver_clear_out = 1'b0; | |
| receiver_isolate_out = 1'b1; | |
| end | |
| CLEAR_PHASE_CLEAR: begin | |
| receiver_clear_out = 1'b1; | |
| receiver_isolate_out = 1'b1; | |
| end | |
| CLEAR_PHASE_POST_CLEAR: begin | |
| receiver_clear_out = 1'b0; | |
| receiver_isolate_out = 1'b1; | |
| end | |
| default: begin | |
| receiver_clear_out = 1'b0; | |
| receiver_isolate_out = 1'b0; | |
| receiver_phase_ack = 1'b0; | |
| end | |
| endcase | |
| end | |
| end | |
| assign clear_o = initiator_clear_out || receiver_clear_out; | |
| assign isolate_o = initiator_isolate_out || receiver_isolate_out; | |
| endmodule : cdc_reset_ctrlr_half | |
| `begin_keywords "1800-2023" | |
| (* no_ungroup *) | |
| (* no_boundary_optimization *) | |
| module cdc_fifo_gray #( | |
| parameter int unsigned WIDTH = 1, | |
| parameter type T = logic [WIDTH-1:0], | |
| parameter int LOG_DEPTH = 3, | |
| parameter int SYNC_STAGES = 2 | |
| ) ( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input T src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| output T dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| T [2**LOG_DEPTH-1:0] async_data; | |
| logic [LOG_DEPTH:0] async_wptr; | |
| logic [LOG_DEPTH:0] async_rptr; | |
| cdc_fifo_gray_src #( | |
| .T ( T ), | |
| .LOG_DEPTH ( LOG_DEPTH ) | |
| ) i_src ( | |
| .src_rst_ni, | |
| .src_clk_i, | |
| .src_data_i, | |
| .src_valid_i, | |
| .src_ready_o, | |
| (* async *) .async_data_o ( async_data ), | |
| (* async *) .async_wptr_o ( async_wptr ), | |
| (* async *) .async_rptr_i ( async_rptr ) | |
| ); | |
| cdc_fifo_gray_dst #( | |
| .T ( T ), | |
| .LOG_DEPTH ( LOG_DEPTH ) | |
| ) i_dst ( | |
| .dst_rst_ni, | |
| .dst_clk_i, | |
| .dst_data_o, | |
| .dst_valid_o, | |
| .dst_ready_i, | |
| (* async *) .async_data_i ( async_data ), | |
| (* async *) .async_wptr_i ( async_wptr ), | |
| (* async *) .async_rptr_o ( async_rptr ) | |
| ); | |
| initial begin | |
| log_depth_0: assert (LOG_DEPTH > 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "log_depth_0", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_fifo_gray.sv", 162); | |
| end | |
| end | |
| initial begin | |
| sync_stages_gt_2: assert (SYNC_STAGES >= 2) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "sync_stages_gt_2", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_fifo_gray.sv", 163); | |
| end | |
| end | |
| endmodule | |
| (* no_ungroup *) | |
| (* no_boundary_optimization *) | |
| module cdc_fifo_gray_src #( | |
| parameter type T = logic, | |
| parameter int LOG_DEPTH = 3, | |
| parameter int SYNC_STAGES = 2 | |
| )( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input T src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| output T [2**LOG_DEPTH-1:0] async_data_o, | |
| output logic [LOG_DEPTH:0] async_wptr_o, | |
| input logic [LOG_DEPTH:0] async_rptr_i | |
| ); | |
| localparam int PtrWidth = LOG_DEPTH+1; | |
| localparam logic [PtrWidth-1:0] PtrFull = (1 << LOG_DEPTH); | |
| T [2**LOG_DEPTH-1:0] data_q, data_d; | |
| logic [PtrWidth-1:0] wptr_q, wptr_d, wptr_bin, wptr_next, rptr, rptr_bin; | |
| assign async_data_o = data_q; | |
| always_comb begin | |
| data_d = data_q; | |
| data_d[wptr_bin[LOG_DEPTH-1:0]] = src_data_i; | |
| end | |
| always_ff @(posedge (src_clk_i) or negedge (src_rst_ni)) begin | |
| if (!src_rst_ni) begin | |
| data_q <= ('0); | |
| end else begin | |
| if (src_valid_i & src_ready_o) begin | |
| data_q <= (data_d); | |
| end | |
| end | |
| end | |
| for (genvar i = 0; i < PtrWidth; i++) begin : gen_sync | |
| sync #(.STAGES(SYNC_STAGES)) i_sync ( | |
| .clk_i ( src_clk_i ), | |
| .rst_ni ( src_rst_ni ), | |
| .serial_i ( async_rptr_i[i] ), | |
| .serial_o ( rptr[i] ) | |
| ); | |
| end | |
| gray_to_binary #(PtrWidth) i_rptr_g2b (.A(rptr), .Z(rptr_bin)); | |
| assign wptr_next = wptr_bin+1; | |
| gray_to_binary #(PtrWidth) i_wptr_g2b (.A(wptr_q), .Z(wptr_bin)); | |
| binary_to_gray #(PtrWidth) i_wptr_b2g (.A(wptr_next), .Z(wptr_d)); | |
| always_ff @(posedge (src_clk_i) or negedge (src_rst_ni)) begin | |
| if (!src_rst_ni) begin | |
| wptr_q <= ('0); | |
| end else begin | |
| if (src_valid_i & src_ready_o) begin | |
| wptr_q <= (wptr_d); | |
| end | |
| end | |
| end | |
| assign async_wptr_o = wptr_q; | |
| assign src_ready_o = ((wptr_bin ^ rptr_bin) != PtrFull); | |
| endmodule | |
| (* no_ungroup *) | |
| (* no_boundary_optimization *) | |
| module cdc_fifo_gray_dst #( | |
| parameter type T = logic, | |
| parameter int LOG_DEPTH = 3, | |
| parameter int SYNC_STAGES = 2 | |
| )( | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| output T dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i, | |
| input T [2**LOG_DEPTH-1:0] async_data_i, | |
| input logic [LOG_DEPTH:0] async_wptr_i, | |
| output logic [LOG_DEPTH:0] async_rptr_o | |
| ); | |
| localparam int PtrWidth = LOG_DEPTH+1; | |
| localparam logic [PtrWidth-1:0] PtrEmpty = '0; | |
| T dst_data; | |
| logic [PtrWidth-1:0] rptr_q, rptr_d, rptr_bin, rptr_bin_d, rptr_next, wptr, wptr_bin; | |
| logic dst_valid, dst_ready; | |
| assign dst_data = async_data_i[rptr_bin[LOG_DEPTH-1:0]]; | |
| assign rptr_next = rptr_bin+1; | |
| gray_to_binary #(PtrWidth) i_rptr_g2b (.A(rptr_q), .Z(rptr_bin)); | |
| binary_to_gray #(PtrWidth) i_rptr_b2g (.A(rptr_next), .Z(rptr_d)); | |
| always_ff @(posedge (dst_clk_i) or negedge (dst_rst_ni)) begin | |
| if (!dst_rst_ni) begin | |
| rptr_q <= ('0); | |
| end else begin | |
| if (dst_valid & dst_ready) begin | |
| rptr_q <= (rptr_d); | |
| end | |
| end | |
| end | |
| assign async_rptr_o = rptr_q; | |
| for (genvar i = 0; i < PtrWidth; i++) begin : gen_sync | |
| sync #(.STAGES(SYNC_STAGES)) i_sync ( | |
| .clk_i ( dst_clk_i ), | |
| .rst_ni ( dst_rst_ni ), | |
| .serial_i ( async_wptr_i[i] ), | |
| .serial_o ( wptr[i] ) | |
| ); | |
| end | |
| gray_to_binary #(PtrWidth) i_wptr_g2b (.A(wptr), .Z(wptr_bin)); | |
| assign dst_valid = ((wptr_bin ^ rptr_bin) != PtrEmpty); | |
| spill_register #( | |
| .T ( T ) | |
| ) i_spill_register ( | |
| .clk_i ( dst_clk_i ), | |
| .rst_ni ( dst_rst_ni ), | |
| .valid_i ( dst_valid ), | |
| .ready_o ( dst_ready ), | |
| .data_i ( dst_data ), | |
| .valid_o ( dst_valid_o ), | |
| .ready_i ( dst_ready_i ), | |
| .data_o ( dst_data_o ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module fall_through_register #( | |
| parameter type T = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic clr_i, | |
| input logic testmode_i, | |
| input logic valid_i, | |
| output logic ready_o, | |
| input T data_i, | |
| output logic valid_o, | |
| input logic ready_i, | |
| output T data_o | |
| ); | |
| logic fifo_empty, | |
| fifo_full; | |
| fifo_v3 #( | |
| .FALL_THROUGH (1'b1), | |
| .DEPTH (1), | |
| .dtype (T) | |
| ) i_fifo ( | |
| .clk_i (clk_i), | |
| .rst_ni (rst_ni), | |
| .flush_i (clr_i), | |
| .testmode_i (testmode_i), | |
| .full_o (fifo_full), | |
| .empty_o (fifo_empty), | |
| .usage_o (), | |
| .data_i (data_i), | |
| .push_i (valid_i & ~fifo_full), | |
| .data_o (data_o), | |
| .pop_i (ready_i & ~fifo_empty) | |
| ); | |
| assign ready_o = ~fifo_full; | |
| assign valid_o = ~fifo_empty; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module id_queue #( | |
| parameter int ID_WIDTH = 0, | |
| parameter int CAPACITY = 0, | |
| parameter bit FULL_BW = 0, | |
| parameter bit CUT_OUP_POP_INP_GNT = 0, | |
| parameter int NUM_CMP_PORTS = 1, | |
| parameter type data_t = logic[31:0], | |
| localparam type id_t = logic[ID_WIDTH-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input id_t inp_id_i, | |
| input data_t inp_data_i, | |
| input logic inp_req_i, | |
| output logic inp_gnt_o, | |
| input data_t [NUM_CMP_PORTS-1:0] exists_data_i, | |
| input data_t [NUM_CMP_PORTS-1:0] exists_mask_i, | |
| input logic [NUM_CMP_PORTS-1:0] exists_req_i, | |
| output logic [NUM_CMP_PORTS-1:0] exists_o, | |
| output logic [NUM_CMP_PORTS-1:0] exists_gnt_o, | |
| input id_t oup_id_i, | |
| input logic oup_pop_i, | |
| input logic oup_req_i, | |
| output data_t oup_data_o, | |
| output logic oup_data_valid_o, | |
| output logic oup_gnt_o, | |
| output logic full_o, | |
| output logic empty_o | |
| ); | |
| localparam int NIds = 2**ID_WIDTH; | |
| localparam int HtCapacity = (NIds <= CAPACITY) ? NIds : CAPACITY; | |
| localparam int unsigned HtIdxWidth = cf_math_pkg::idx_width(HtCapacity); | |
| localparam int unsigned LdIdxWidth = cf_math_pkg::idx_width(CAPACITY); | |
| typedef logic [HtIdxWidth-1:0] ht_idx_t; | |
| typedef logic [LdIdxWidth-1:0] ld_idx_t; | |
| typedef struct packed { | |
| id_t id; | |
| ld_idx_t head, | |
| tail; | |
| logic free; | |
| } head_tail_t; | |
| typedef struct packed { | |
| data_t data; | |
| ld_idx_t next; | |
| logic free; | |
| } linked_data_t; | |
| head_tail_t [HtCapacity-1:0] head_tail_d, head_tail_q; | |
| linked_data_t [CAPACITY-1:0] linked_data_d, linked_data_q; | |
| logic full, | |
| match_in_id_valid, | |
| match_out_id_valid, | |
| no_in_id_match, | |
| no_out_id_match; | |
| logic [HtCapacity-1:0] head_tail_free, | |
| idx_matches_in_id, | |
| idx_matches_out_id; | |
| logic [NUM_CMP_PORTS-1:0][CAPACITY-1:0] exists_match; | |
| logic [CAPACITY-1:0] linked_data_free; | |
| id_t match_in_id, match_out_id; | |
| ht_idx_t head_tail_free_idx, | |
| match_in_idx, | |
| match_out_idx; | |
| ld_idx_t linked_data_free_idx, | |
| oup_data_free_idx; | |
| logic oup_data_popped, | |
| oup_ht_popped; | |
| for (genvar i = 0; i < HtCapacity; i++) begin: gen_idx_match | |
| assign idx_matches_in_id[i] = match_in_id_valid && (head_tail_q[i].id == match_in_id) && | |
| !head_tail_q[i].free; | |
| assign idx_matches_out_id[i] = match_out_id_valid && (head_tail_q[i].id == match_out_id) && | |
| !head_tail_q[i].free; | |
| end | |
| assign no_in_id_match = !(|idx_matches_in_id); | |
| assign no_out_id_match = !(|idx_matches_out_id); | |
| onehot_to_bin #( | |
| .ONEHOT_WIDTH ( HtCapacity ) | |
| ) i_id_ohb_in ( | |
| .onehot ( idx_matches_in_id ), | |
| .bin ( match_in_idx ) | |
| ); | |
| onehot_to_bin #( | |
| .ONEHOT_WIDTH ( HtCapacity ) | |
| ) i_id_ohb_out ( | |
| .onehot ( idx_matches_out_id ), | |
| .bin ( match_out_idx ) | |
| ); | |
| for (genvar i = 0; i < HtCapacity; i++) begin: gen_head_tail_free | |
| assign head_tail_free[i] = head_tail_q[i].free; | |
| end | |
| lzc #( | |
| .WIDTH ( HtCapacity ), | |
| .MODE ( 0 ) | |
| ) i_ht_free_lzc ( | |
| .in_i ( head_tail_free ), | |
| .cnt_o ( head_tail_free_idx ), | |
| .empty_o ( ) | |
| ); | |
| for (genvar i = 0; i < CAPACITY; i++) begin: gen_linked_data_free | |
| assign linked_data_free[i] = linked_data_q[i].free; | |
| end | |
| lzc #( | |
| .WIDTH ( CAPACITY ), | |
| .MODE ( 0 ) | |
| ) i_ld_free_lzc ( | |
| .in_i ( linked_data_free ), | |
| .cnt_o ( linked_data_free_idx ), | |
| .empty_o ( ) | |
| ); | |
| assign full = !(|linked_data_free); | |
| assign empty = &linked_data_free; | |
| assign oup_data_free_idx = head_tail_q[match_out_idx].head; | |
| assign inp_gnt_o = ~full || (oup_data_popped && FULL_BW && ~CUT_OUP_POP_INP_GNT); | |
| always_comb begin | |
| match_in_id = '0; | |
| match_out_id = '0; | |
| match_in_id_valid = 1'b0; | |
| match_out_id_valid = 1'b0; | |
| head_tail_d = head_tail_q; | |
| linked_data_d = linked_data_q; | |
| oup_gnt_o = 1'b0; | |
| oup_data_o = data_t'('0); | |
| oup_data_valid_o = 1'b0; | |
| oup_data_popped = 1'b0; | |
| oup_ht_popped = 1'b0; | |
| if (!FULL_BW) begin | |
| if (inp_req_i && !full) begin | |
| match_in_id = inp_id_i; | |
| match_in_id_valid = 1'b1; | |
| if (no_in_id_match) begin | |
| head_tail_d[head_tail_free_idx] = '{ | |
| id: inp_id_i, | |
| head: linked_data_free_idx, | |
| tail: linked_data_free_idx, | |
| free: 1'b0 | |
| }; | |
| end else begin | |
| linked_data_d[head_tail_q[match_in_idx].tail].next = linked_data_free_idx; | |
| head_tail_d[match_in_idx].tail = linked_data_free_idx; | |
| end | |
| linked_data_d[linked_data_free_idx] = '{ | |
| data: inp_data_i, | |
| next: '0, | |
| free: 1'b0 | |
| }; | |
| end else if (oup_req_i) begin | |
| match_in_id = oup_id_i; | |
| match_in_id_valid = 1'b1; | |
| if (!no_in_id_match) begin | |
| oup_data_o = data_t'(linked_data_q[head_tail_q[match_in_idx].head].data); | |
| oup_data_valid_o = 1'b1; | |
| if (oup_pop_i) begin | |
| linked_data_d[head_tail_q[match_in_idx].head] = '0; | |
| linked_data_d[head_tail_q[match_in_idx].head].free = 1'b1; | |
| if (head_tail_q[match_in_idx].head == head_tail_q[match_in_idx].tail) begin | |
| head_tail_d[match_in_idx] = '{free: 1'b1, default: '0}; | |
| end else begin | |
| head_tail_d[match_in_idx].head = | |
| linked_data_q[head_tail_q[match_in_idx].head].next; | |
| end | |
| end | |
| end | |
| oup_gnt_o = 1'b1; | |
| end | |
| end else begin | |
| if (oup_req_i) begin | |
| match_out_id = oup_id_i; | |
| match_out_id_valid = 1'b1; | |
| if (!no_out_id_match) begin | |
| oup_data_o = data_t'(linked_data_q[head_tail_q[match_out_idx].head].data); | |
| oup_data_valid_o = 1'b1; | |
| if (oup_pop_i) begin | |
| oup_data_popped = 1'b1; | |
| linked_data_d[head_tail_q[match_out_idx].head] = '0; | |
| linked_data_d[head_tail_q[match_out_idx].head].free = 1'b1; | |
| if (head_tail_q[match_out_idx].head | |
| == head_tail_q[match_out_idx].tail) begin | |
| oup_ht_popped = 1'b1; | |
| head_tail_d[match_out_idx] = '{free: 1'b1, default: '0}; | |
| end else begin | |
| head_tail_d[match_out_idx].head = | |
| linked_data_q[head_tail_q[match_out_idx].head].next; | |
| end | |
| end | |
| end | |
| oup_gnt_o = 1'b1; | |
| end | |
| if (inp_req_i && inp_gnt_o) begin | |
| match_in_id = inp_id_i; | |
| match_in_id_valid = 1'b1; | |
| if (oup_ht_popped && (oup_id_i==inp_id_i)) begin | |
| head_tail_d[match_out_idx] = '{ | |
| id: inp_id_i, | |
| head: oup_data_free_idx, | |
| tail: oup_data_free_idx, | |
| free: 1'b0 | |
| }; | |
| linked_data_d[oup_data_free_idx] = '{ | |
| data: inp_data_i, | |
| next: '0, | |
| free: 1'b0 | |
| }; | |
| end else if (no_in_id_match) begin | |
| if (oup_ht_popped) begin | |
| head_tail_d[match_out_idx] = '{ | |
| id: inp_id_i, | |
| head: oup_data_free_idx, | |
| tail: oup_data_free_idx, | |
| free: 1'b0 | |
| }; | |
| linked_data_d[oup_data_free_idx] = '{ | |
| data: inp_data_i, | |
| next: '0, | |
| free: 1'b0 | |
| }; | |
| end else begin | |
| if (oup_data_popped) begin | |
| head_tail_d[head_tail_free_idx] = '{ | |
| id: inp_id_i, | |
| head: oup_data_free_idx, | |
| tail: oup_data_free_idx, | |
| free: 1'b0 | |
| }; | |
| linked_data_d[oup_data_free_idx] = '{ | |
| data: inp_data_i, | |
| next: '0, | |
| free: 1'b0 | |
| }; | |
| end else begin | |
| head_tail_d[head_tail_free_idx] = '{ | |
| id: inp_id_i, | |
| head: linked_data_free_idx, | |
| tail: linked_data_free_idx, | |
| free: 1'b0 | |
| }; | |
| linked_data_d[linked_data_free_idx] = '{ | |
| data: inp_data_i, | |
| next: '0, | |
| free: 1'b0 | |
| }; | |
| end | |
| end | |
| end else begin | |
| if (oup_data_popped) begin | |
| linked_data_d[head_tail_q[match_in_idx].tail].next = oup_data_free_idx; | |
| head_tail_d[match_in_idx].tail = oup_data_free_idx; | |
| linked_data_d[oup_data_free_idx] = '{ | |
| data: inp_data_i, | |
| next: '0, | |
| free: 1'b0 | |
| }; | |
| end else begin | |
| linked_data_d[head_tail_q[match_in_idx].tail].next = linked_data_free_idx; | |
| head_tail_d[match_in_idx].tail = linked_data_free_idx; | |
| linked_data_d[linked_data_free_idx] = '{ | |
| data: inp_data_i, | |
| next: '0, | |
| free: 1'b0 | |
| }; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| for (genvar k = 0; k < NUM_CMP_PORTS; k++) begin: gen_lookup_port | |
| for (genvar i = 0; i < CAPACITY; i++) begin: gen_lookup | |
| assign exists_match[k][i] = ~linked_data_q[i].free & | |
| ((linked_data_q[i].data & exists_mask_i[k]) == | |
| (exists_data_i[k] & exists_mask_i[k])); | |
| end | |
| always_comb begin | |
| exists_gnt_o[k] = 1'b0; | |
| exists_o[k] = '0; | |
| if (exists_req_i[k]) begin | |
| exists_gnt_o[k] = 1'b1; | |
| exists_o[k] = (|exists_match[k]); | |
| end | |
| end | |
| end | |
| for (genvar i = 0; i < HtCapacity; i++) begin: gen_ht_ffs | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| head_tail_q[i] <= '{free: 1'b1, default: '0}; | |
| end else begin | |
| head_tail_q[i] <= head_tail_d[i]; | |
| end | |
| end | |
| end | |
| for (genvar i = 0; i < CAPACITY; i++) begin: gen_data_ffs | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| linked_data_q[i] <= '0; | |
| linked_data_q[i].free <= 1'b1; | |
| end else begin | |
| linked_data_q[i] <= linked_data_d[i]; | |
| end | |
| end | |
| end | |
| assign full_o = full; | |
| assign empty_o = empty; | |
| initial begin | |
| id_width_0: assert (ID_WIDTH >= 1) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "id_width_0", "The ID must at least be one bit wide!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/id_queue.sv", 414); | |
| end | |
| end | |
| initial begin | |
| capacity_0: assert (CAPACITY >= 1) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "capacity_0", "The queue must have capacity of at least one entry!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/id_queue.sv", 415); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_to_mem #( | |
| parameter type mem_req_t = logic, | |
| parameter type mem_resp_t = logic, | |
| parameter int unsigned BufDepth = 32'd1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input mem_req_t req_i, | |
| input logic req_valid_i, | |
| output logic req_ready_o, | |
| output mem_resp_t resp_o, | |
| output logic resp_valid_o, | |
| input logic resp_ready_i, | |
| output mem_req_t mem_req_o, | |
| output logic mem_req_valid_o, | |
| input logic mem_req_ready_i, | |
| input mem_resp_t mem_resp_i, | |
| input logic mem_resp_valid_i | |
| ); | |
| typedef logic [$clog2(BufDepth+1):0] cnt_t; | |
| cnt_t cnt_d, cnt_q; | |
| logic buf_ready, | |
| req_ready; | |
| if (BufDepth > 0) begin : gen_buf | |
| always_comb begin | |
| cnt_d = cnt_q; | |
| if (req_valid_i && req_ready_o) begin | |
| cnt_d++; | |
| end | |
| if (resp_valid_o && resp_ready_i) begin | |
| cnt_d--; | |
| end | |
| end | |
| assign req_ready = (cnt_q < BufDepth) | (resp_valid_o & resp_ready_i); | |
| assign req_ready_o = mem_req_ready_i & req_ready; | |
| assign mem_req_valid_o = req_valid_i & req_ready; | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b1 ), | |
| .DEPTH ( BufDepth ), | |
| .T ( mem_resp_t ) | |
| ) i_resp_buf ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .data_i ( mem_resp_i ), | |
| .valid_i ( mem_resp_valid_i ), | |
| .ready_o ( buf_ready ), | |
| .data_o ( resp_o ), | |
| .valid_o ( resp_valid_o ), | |
| .ready_i ( resp_ready_i ), | |
| .usage_o ( ) | |
| ); | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| cnt_q <= ('0); | |
| end else begin | |
| cnt_q <= (cnt_d); | |
| end | |
| end | |
| end else begin : gen_no_buf | |
| assign mem_req_valid_o = req_valid_i; | |
| assign resp_valid_o = mem_req_valid_o & mem_req_ready_i & mem_resp_valid_i; | |
| assign req_ready_o = resp_ready_i & resp_valid_o; | |
| assign resp_o = mem_resp_i; | |
| end | |
| assign mem_req_o = req_i; | |
| if (BufDepth > 0) begin : gen_buf_asserts | |
| memory_response_lost: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (mem_resp_valid_i |-> buf_ready)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "memory_response_lost", "Memory response lost!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_to_mem.sv", 124); | |
| end | |
| counter_underflowed: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (cnt_q == '0 |=> cnt_q != '1)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "counter_underflowed", "Counter underflowed!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_to_mem.sv", 126); | |
| end | |
| counter_overflowed: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (cnt_q == BufDepth |=> cnt_q != BufDepth + 1)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "counter_overflowed", "Counter overflowed!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_to_mem.sv", 128); | |
| end | |
| end else begin : gen_no_buf_asserts | |
| no_memory_response: assume property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (mem_req_valid_o & mem_req_ready_i |-> mem_resp_valid_i)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "no_memory_response", "Without BufDepth = 0, the memory must respond in the same cycle!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_to_mem.sv", 131); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_arbiter_flushable #( | |
| parameter type DATA_T = logic, | |
| parameter integer N_INP = -1, | |
| parameter ARBITER = "rr" | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input DATA_T [N_INP-1:0] inp_data_i, | |
| input logic [N_INP-1:0] inp_valid_i, | |
| output logic [N_INP-1:0] inp_ready_o, | |
| output DATA_T oup_data_o, | |
| output logic oup_valid_o, | |
| input logic oup_ready_i | |
| ); | |
| if (ARBITER == "rr") begin : gen_rr_arb | |
| rr_arb_tree #( | |
| .NumIn (N_INP), | |
| .DataType (DATA_T), | |
| .ExtPrio (1'b0), | |
| .AxiVldRdy (1'b1), | |
| .LockIn (1'b1) | |
| ) i_arbiter ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .rr_i ('0), | |
| .req_i (inp_valid_i), | |
| .gnt_o (inp_ready_o), | |
| .data_i (inp_data_i), | |
| .gnt_i (oup_ready_i), | |
| .req_o (oup_valid_o), | |
| .data_o (oup_data_o), | |
| .idx_o () | |
| ); | |
| end else if (ARBITER == "prio") begin : gen_prio_arb | |
| rr_arb_tree #( | |
| .NumIn (N_INP), | |
| .DataType (DATA_T), | |
| .ExtPrio (1'b1), | |
| .AxiVldRdy (1'b1), | |
| .LockIn (1'b0) | |
| ) i_arbiter ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .rr_i ('0), | |
| .req_i (inp_valid_i), | |
| .gnt_o (inp_ready_o), | |
| .data_i (inp_data_i), | |
| .gnt_i (oup_ready_i), | |
| .req_o (oup_valid_o), | |
| .data_o (oup_data_o), | |
| .idx_o () | |
| ); | |
| end else begin : gen_arb_error | |
| $fatal(1, "Invalid value for parameter 'ARBITER'!"); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_fifo_optimal_wrap #( | |
| parameter int unsigned Depth = 32'd8, | |
| parameter type type_t = logic, | |
| parameter bit PrintInfo = 1'b0, | |
| parameter int unsigned AddrDepth = (Depth > 32'd1) ? $clog2(Depth) : 32'd1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input logic testmode_i, | |
| output logic [AddrDepth-1:0] usage_o, | |
| input type_t data_i, | |
| input logic valid_i, | |
| output logic ready_o, | |
| output type_t data_o, | |
| output logic valid_o, | |
| input logic ready_i | |
| ); | |
| if (Depth < 32'd2) begin : gen_fatal | |
| initial begin | |
| $fatal(1, "FIFO of depth %d does not make any sense!", Depth); | |
| end | |
| end | |
| if (Depth == 32'd2) begin : gen_spill | |
| if (PrintInfo) begin : gen_info | |
| initial begin | |
| $display("[%m] Instantiate spill register (of depth %d)", Depth); | |
| end | |
| end | |
| spill_register_flushable #( | |
| .T ( type_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_spill_register_flushable ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .valid_i, | |
| .ready_o, | |
| .data_i, | |
| .valid_o, | |
| .ready_i, | |
| .data_o | |
| ); | |
| assign usage_o = 'x; | |
| end | |
| if (Depth > 32'd2) begin : gen_fifo | |
| if (PrintInfo) begin : gen_info | |
| initial begin | |
| $info("[%m] Instantiate stream FIFO of depth %d", Depth); | |
| end | |
| end | |
| stream_fifo #( | |
| .DEPTH ( Depth ), | |
| .T ( type_t ) | |
| ) i_stream_fifo ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .testmode_i, | |
| .usage_o, | |
| .data_i, | |
| .valid_i, | |
| .ready_o, | |
| .data_o, | |
| .valid_o, | |
| .ready_i | |
| ); | |
| end | |
| endmodule : stream_fifo_optimal_wrap | |
| `begin_keywords "1800-2023" | |
| module stream_register #( | |
| parameter type T = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic clr_i, | |
| input logic testmode_i, | |
| input logic valid_i, | |
| output logic ready_o, | |
| input T data_i, | |
| output logic valid_o, | |
| input logic ready_i, | |
| output T data_o | |
| ); | |
| logic reg_ena; | |
| assign ready_o = ready_i | ~valid_o; | |
| assign reg_ena = valid_i & ready_o; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| valid_o <= (1'b0); | |
| end else begin | |
| if (clr_i) begin | |
| valid_o <= (1'b0); | |
| end else if (ready_o) begin | |
| valid_o <= (valid_i); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| data_o <= (T'('0)); | |
| end else begin | |
| if (clr_i) begin | |
| data_o <= (T'('0)); | |
| end else if (reg_ena) begin | |
| data_o <= (data_i); | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_xbar #( | |
| parameter int unsigned NumInp = 32'd0, | |
| parameter int unsigned NumOut = 32'd0, | |
| parameter int unsigned DataWidth = 32'd1, | |
| parameter type payload_t = logic [DataWidth-1:0], | |
| parameter bit OutSpillReg = 1'b0, | |
| parameter int unsigned ExtPrio = 1'b0, | |
| parameter int unsigned AxiVldRdy = 1'b1, | |
| parameter int unsigned LockIn = 1'b1, | |
| parameter payload_t AxiVldMask = '1, | |
| parameter int unsigned SelWidth = (NumOut > 32'd1) ? unsigned'($clog2(NumOut)) : 32'd1, | |
| parameter type sel_oup_t = logic[SelWidth-1:0], | |
| parameter int unsigned IdxWidth = (NumInp > 32'd1) ? unsigned'($clog2(NumInp)) : 32'd1, | |
| parameter type idx_inp_t = logic[IdxWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input idx_inp_t [NumOut-1:0] rr_i, | |
| input payload_t [NumInp-1:0] data_i, | |
| input sel_oup_t [NumInp-1:0] sel_i, | |
| input logic [NumInp-1:0] valid_i, | |
| output logic [NumInp-1:0] ready_o, | |
| output payload_t [NumOut-1:0] data_o, | |
| output idx_inp_t [NumOut-1:0] idx_o, | |
| output logic [NumOut-1:0] valid_o, | |
| input logic [NumOut-1:0] ready_i | |
| ); | |
| typedef struct packed { | |
| payload_t data; | |
| idx_inp_t idx; | |
| } spill_data_t; | |
| logic [NumInp-1:0][NumOut-1:0] inp_valid; | |
| logic [NumInp-1:0][NumOut-1:0] inp_ready; | |
| payload_t [NumOut-1:0][NumInp-1:0] out_data; | |
| logic [NumOut-1:0][NumInp-1:0] out_valid; | |
| logic [NumOut-1:0][NumInp-1:0] out_ready; | |
| for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_inps | |
| stream_demux #( | |
| .N_OUP ( NumOut ) | |
| ) i_stream_demux ( | |
| .inp_valid_i ( valid_i[i] ), | |
| .inp_ready_o ( ready_o[i] ), | |
| .oup_sel_i ( sel_i[i] ), | |
| .oup_valid_o ( inp_valid[i] ), | |
| .oup_ready_i ( inp_ready[i] ) | |
| ); | |
| for (genvar j = 0; unsigned'(j) < NumOut; j++) begin : gen_cross | |
| assign out_data[j][i] = data_i[i]; | |
| assign out_valid[j][i] = inp_valid[i][j]; | |
| assign inp_ready[i][j] = out_ready[j][i]; | |
| end | |
| end | |
| for (genvar j = 0; unsigned'(j) < NumOut; j++) begin : gen_outs | |
| spill_data_t arb; | |
| logic arb_valid, arb_ready; | |
| rr_arb_tree #( | |
| .NumIn ( NumInp ), | |
| .DataType ( payload_t ), | |
| .ExtPrio ( ExtPrio ), | |
| .AxiVldRdy ( AxiVldRdy ), | |
| .LockIn ( LockIn ) | |
| ) i_rr_arb_tree ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .rr_i ( rr_i[j] ), | |
| .req_i ( out_valid[j] ), | |
| .gnt_o ( out_ready[j] ), | |
| .data_i ( out_data[j] ), | |
| .req_o ( arb_valid ), | |
| .gnt_i ( arb_ready ), | |
| .data_o ( arb.data ), | |
| .idx_o ( arb.idx ) | |
| ); | |
| spill_data_t spill; | |
| spill_register #( | |
| .T ( spill_data_t ), | |
| .Bypass ( !OutSpillReg ) | |
| ) i_spill_register ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( arb_valid ), | |
| .ready_o ( arb_ready ), | |
| .data_i ( arb ), | |
| .valid_o ( valid_o[j] ), | |
| .ready_i ( ready_i[j] ), | |
| .data_o ( spill ) | |
| ); | |
| always_comb begin | |
| data_o[j] = spill.data; | |
| idx_o[j] = spill.idx; | |
| end | |
| end | |
| for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_sel_assertions | |
| non_existing_output: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_i[i] |-> sel_i[i] < NumOut)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "non_existing_output", "Non-existing output is selected!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 176); | |
| end | |
| end | |
| if (AxiVldRdy) begin : gen_handshake_assertions | |
| for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_inp_assertions | |
| input_data_unstable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_i[i] && !ready_o[i] |=> $stable(data_i[i] & AxiVldMask))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "input_data_unstable", $sformatf("data_i is unstable at input: %0d", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 182); | |
| end | |
| input_sel_unstable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_i[i] && !ready_o[i] |=> $stable(sel_i[i]))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "input_sel_unstable", $sformatf("sel_i is unstable at input: %0d", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 184); | |
| end | |
| input_valid_taken: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_i[i] && !ready_o[i] |=> valid_i[i])) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "input_valid_taken", $sformatf("valid_i at input %0d has been taken away without a ready.", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 186); | |
| end | |
| end | |
| for (genvar i = 0; unsigned'(i) < NumOut; i++) begin : gen_out_assertions | |
| output_data_unstable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_o[i] && !ready_i[i] |=> $stable(data_o[i] & AxiVldMask))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "output_data_unstable", $sformatf("data_o is unstable at output: %0d Check that parameter LockIn is set.", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 191); | |
| end | |
| output_idx_unstable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_o[i] && !ready_i[i] |=> $stable(idx_o[i]))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "output_idx_unstable", $sformatf("idx_o is unstable at output: %0d Check that parameter LockIn is set.", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 193); | |
| end | |
| output_valid_taken: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_o[i] && !ready_i[i] |=> valid_o[i])) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "output_valid_taken", $sformatf("valid_o at output %0d has been taken away without a ready.", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 195); | |
| end | |
| end | |
| end | |
| initial begin | |
| numinp_0: assert (NumInp > 32'd0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "numinp_0", "NumInp has to be > 0!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 199); | |
| end | |
| end | |
| initial begin | |
| numout_0: assert (NumOut > 32'd0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "numout_0", "NumOut has to be > 0!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_xbar.sv", 200); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| (* no_ungroup *) | |
| (* no_boundary_optimization *) | |
| module cdc_fifo_gray_clearable #( | |
| parameter int unsigned WIDTH = 1, | |
| parameter type T = logic [WIDTH-1:0], | |
| parameter int LOG_DEPTH = 3, | |
| parameter int SYNC_STAGES = 3, | |
| parameter int CLEAR_ON_ASYNC_RESET = 1 | |
| ) ( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input logic src_clear_i, | |
| output logic src_clear_pending_o, | |
| input T src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| input logic dst_clear_i, | |
| output logic dst_clear_pending_o, | |
| output T dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| logic s_src_clear_req; | |
| logic s_src_clear_ack_q; | |
| logic s_src_ready; | |
| logic s_src_isolate_req; | |
| logic s_src_isolate_ack_q; | |
| logic s_dst_clear_req; | |
| logic s_dst_clear_ack_q; | |
| logic s_dst_valid; | |
| logic s_dst_isolate_req; | |
| logic s_dst_isolate_ack_q; | |
| T [2**LOG_DEPTH-1:0] async_data; | |
| logic [LOG_DEPTH:0] async_wptr; | |
| logic [LOG_DEPTH:0] async_rptr; | |
| if (CLEAR_ON_ASYNC_RESET) begin : gen_elaboration_assertion | |
| if (SYNC_STAGES < 3) | |
| $error("The clearable CDC FIFO with async reset synchronization requires at least", | |
| "3 synchronizer stages for the FIFO."); | |
| end else begin : gen_elaboration_assertion | |
| if (SYNC_STAGES < 2) begin : gen_elaboration_assertion | |
| $error("A minimum of 2 synchronizer stages is required for proper functionality."); | |
| end | |
| end | |
| if (2*SYNC_STAGES > 2**LOG_DEPTH) begin : gen_elaboration_assertion2 | |
| $warning("The FIFOs depth of %0d is insufficient to completely hide the latency of", | |
| " %0d SYNC_STAGES. The FIFO will stall in the case where f_src ~= f_dst. ", | |
| "It is reccomended to increase the FIFO's log depth to at least %0d.", | |
| 2**LOG_DEPTH, SYNC_STAGES, $clog2(2*SYNC_STAGES)); | |
| end | |
| cdc_fifo_gray_src_clearable #( | |
| .T ( T ), | |
| .LOG_DEPTH ( LOG_DEPTH ), | |
| .SYNC_STAGES ( SYNC_STAGES ) | |
| ) i_src ( | |
| .src_rst_ni, | |
| .src_clk_i, | |
| .src_clear_i ( s_src_clear_req ), | |
| .src_data_i, | |
| .src_valid_i ( src_valid_i & !s_src_isolate_req ), | |
| .src_ready_o ( s_src_ready ), | |
| (* async *) .async_data_o ( async_data ), | |
| (* async *) .async_wptr_o ( async_wptr ), | |
| (* async *) .async_rptr_i ( async_rptr ) | |
| ); | |
| assign src_ready_o = s_src_ready & !s_src_isolate_req; | |
| cdc_fifo_gray_dst_clearable #( | |
| .T ( T ), | |
| .LOG_DEPTH ( LOG_DEPTH ), | |
| .SYNC_STAGES ( SYNC_STAGES ) | |
| ) i_dst ( | |
| .dst_rst_ni, | |
| .dst_clk_i, | |
| .dst_clear_i ( s_dst_clear_req ), | |
| .dst_data_o, | |
| .dst_valid_o ( s_dst_valid ), | |
| .dst_ready_i ( dst_ready_i & !s_dst_isolate_req ), | |
| (* async *) .async_data_i ( async_data ), | |
| (* async *) .async_wptr_i ( async_wptr ), | |
| (* async *) .async_rptr_o ( async_rptr ) | |
| ); | |
| assign dst_valid_o = s_dst_valid & !s_dst_isolate_req; | |
| cdc_reset_ctrlr #( | |
| .SYNC_STAGES(SYNC_STAGES-1) | |
| ) i_cdc_reset_ctrlr ( | |
| .a_clk_i ( src_clk_i ), | |
| .a_rst_ni ( src_rst_ni ), | |
| .a_clear_i ( src_clear_i ), | |
| .a_clear_o ( s_src_clear_req ), | |
| .a_clear_ack_i ( s_src_clear_ack_q ), | |
| .a_isolate_o ( s_src_isolate_req ), | |
| .a_isolate_ack_i ( s_src_isolate_ack_q ), | |
| .b_clk_i ( dst_clk_i ), | |
| .b_rst_ni ( dst_rst_ni ), | |
| .b_clear_i ( dst_clear_i ), | |
| .b_clear_o ( s_dst_clear_req ), | |
| .b_clear_ack_i ( s_dst_clear_ack_q ), | |
| .b_isolate_o ( s_dst_isolate_req ), | |
| .b_isolate_ack_i ( s_dst_isolate_ack_q ) | |
| ); | |
| always_ff @(posedge src_clk_i, negedge src_rst_ni) begin | |
| if (!src_rst_ni) begin | |
| s_src_isolate_ack_q <= 1'b0; | |
| s_src_clear_ack_q <= 1'b0; | |
| end else begin | |
| s_src_isolate_ack_q <= s_src_isolate_req; | |
| s_src_clear_ack_q <= s_src_clear_req; | |
| end | |
| end | |
| always_ff @(posedge dst_clk_i, negedge dst_rst_ni) begin | |
| if (!dst_rst_ni) begin | |
| s_dst_isolate_ack_q <= 1'b0; | |
| s_dst_clear_ack_q <= 1'b0; | |
| end else begin | |
| s_dst_isolate_ack_q <= s_dst_isolate_req; | |
| s_dst_clear_ack_q <= s_dst_clear_req; | |
| end | |
| end | |
| assign src_clear_pending_o = s_src_isolate_req; | |
| assign dst_clear_pending_o = s_dst_isolate_req; | |
| initial begin | |
| log_depth_0: assert (LOG_DEPTH > 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "log_depth_0", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_fifo_gray_clearable.sv", 259); | |
| end | |
| end | |
| initial begin | |
| sync_stages_lt_2: assert (SYNC_STAGES >= 2) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "sync_stages_lt_2", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_fifo_gray_clearable.sv", 260); | |
| end | |
| end | |
| endmodule | |
| (* no_ungroup *) | |
| (* no_boundary_optimization *) | |
| module cdc_fifo_gray_src_clearable #( | |
| parameter type T = logic, | |
| parameter int LOG_DEPTH = 3, | |
| parameter int SYNC_STAGES = 2 | |
| )( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input logic src_clear_i, | |
| input T src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| output T [2**LOG_DEPTH-1:0] async_data_o, | |
| output logic [LOG_DEPTH:0] async_wptr_o, | |
| input logic [LOG_DEPTH:0] async_rptr_i | |
| ); | |
| localparam int PtrWidth = LOG_DEPTH+1; | |
| localparam logic [PtrWidth-1:0] PtrFull = (1 << LOG_DEPTH); | |
| T [2**LOG_DEPTH-1:0] data_q, data_d; | |
| logic [PtrWidth-1:0] wptr_q, wptr_d, wptr_bin, wptr_next, rptr, rptr_bin; | |
| assign async_data_o = data_q; | |
| always_comb begin | |
| data_d = data_q; | |
| data_d[wptr_bin[LOG_DEPTH-1:0]] = src_data_i; | |
| end | |
| always_ff @(posedge (src_clk_i) or negedge (src_rst_ni)) begin | |
| if (!src_rst_ni) begin | |
| data_q <= ('0); | |
| end else begin | |
| if (src_valid_i & src_ready_o) begin | |
| data_q <= (data_d); | |
| end | |
| end | |
| end | |
| for (genvar i = 0; i < PtrWidth; i++) begin : gen_sync | |
| sync #(.STAGES(SYNC_STAGES)) i_sync ( | |
| .clk_i ( src_clk_i ), | |
| .rst_ni ( src_rst_ni ), | |
| .serial_i ( async_rptr_i[i] ), | |
| .serial_o ( rptr[i] ) | |
| ); | |
| end | |
| gray_to_binary #(PtrWidth) i_rptr_g2b (.A(rptr), .Z(rptr_bin)); | |
| assign wptr_next = wptr_bin+1; | |
| gray_to_binary #(PtrWidth) i_wptr_g2b (.A(wptr_q), .Z(wptr_bin)); | |
| binary_to_gray #(PtrWidth) i_wptr_b2g (.A(wptr_next), .Z(wptr_d)); | |
| always_ff @(posedge (src_clk_i) or negedge (src_rst_ni)) begin | |
| if (!src_rst_ni) begin | |
| wptr_q <= ('0); | |
| end else begin | |
| if (src_clear_i) begin | |
| wptr_q <= ('0); | |
| end else if (src_valid_i & src_ready_o) begin | |
| wptr_q <= (wptr_d); | |
| end | |
| end | |
| end | |
| assign async_wptr_o = wptr_q; | |
| assign src_ready_o = ((wptr_bin ^ rptr_bin) != PtrFull); | |
| endmodule | |
| (* no_ungroup *) | |
| (* no_boundary_optimization *) | |
| module cdc_fifo_gray_dst_clearable #( | |
| parameter type T = logic, | |
| parameter int LOG_DEPTH = 3, | |
| parameter int SYNC_STAGES = 2 | |
| )( | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| input logic dst_clear_i, | |
| output T dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i, | |
| input T [2**LOG_DEPTH-1:0] async_data_i, | |
| input logic [LOG_DEPTH:0] async_wptr_i, | |
| output logic [LOG_DEPTH:0] async_rptr_o | |
| ); | |
| localparam int PtrWidth = LOG_DEPTH+1; | |
| localparam logic [PtrWidth-1:0] PtrEmpty = '0; | |
| T dst_data; | |
| logic [PtrWidth-1:0] rptr_q, rptr_d, rptr_bin, rptr_next, wptr, wptr_bin; | |
| logic dst_valid, dst_ready; | |
| assign dst_data = async_data_i[rptr_bin[LOG_DEPTH-1:0]]; | |
| assign rptr_next = rptr_bin+1; | |
| gray_to_binary #(PtrWidth) i_rptr_g2b (.A(rptr_q), .Z(rptr_bin)); | |
| binary_to_gray #(PtrWidth) i_rptr_b2g (.A(rptr_next), .Z(rptr_d)); | |
| always_ff @(posedge (dst_clk_i) or negedge (dst_rst_ni)) begin | |
| if (!dst_rst_ni) begin | |
| rptr_q <= ('0); | |
| end else begin | |
| if (dst_clear_i) begin | |
| rptr_q <= ('0); | |
| end else if (dst_valid & dst_ready) begin | |
| rptr_q <= (rptr_d); | |
| end | |
| end | |
| end | |
| assign async_rptr_o = rptr_q; | |
| for (genvar i = 0; i < PtrWidth; i++) begin : gen_sync | |
| sync #(.STAGES(SYNC_STAGES)) i_sync ( | |
| .clk_i ( dst_clk_i ), | |
| .rst_ni ( dst_rst_ni ), | |
| .serial_i ( async_wptr_i[i] ), | |
| .serial_o ( wptr[i] ) | |
| ); | |
| end | |
| gray_to_binary #(PtrWidth) i_wptr_g2b (.A(wptr), .Z(wptr_bin)); | |
| assign dst_valid = ((wptr_bin ^ rptr_bin) != PtrEmpty); | |
| spill_register_flushable #( | |
| .T ( T ) | |
| ) i_spill_register ( | |
| .clk_i ( dst_clk_i ), | |
| .rst_ni ( dst_rst_ni ), | |
| .flush_i ( dst_clear_i ), | |
| .valid_i ( dst_valid & !dst_clear_i ), | |
| .ready_o ( dst_ready ), | |
| .data_i ( dst_data ), | |
| .valid_o ( dst_valid_o ), | |
| .ready_i ( dst_ready_i ), | |
| .data_o ( dst_data_o ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| /*verilator lint_off DECLFILENAME*/ | |
| module cdc_2phase_clearable #( | |
| parameter type T = logic, | |
| parameter int unsigned SYNC_STAGES = 3, | |
| parameter int CLEAR_ON_ASYNC_RESET = 1 | |
| )( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input logic src_clear_i, | |
| output logic src_clear_pending_o, | |
| input T src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| input logic dst_clear_i, | |
| output logic dst_clear_pending_o, | |
| output T dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| logic s_src_clear_req; | |
| logic s_src_clear_ack_q; | |
| logic s_src_ready; | |
| logic s_src_isolate_req; | |
| logic s_src_isolate_ack_q; | |
| logic s_dst_clear_req; | |
| logic s_dst_clear_ack_q; | |
| logic s_dst_valid; | |
| logic s_dst_isolate_req; | |
| logic s_dst_isolate_ack_q; | |
| (* dont_touch = "true" *) logic async_req; | |
| (* dont_touch = "true" *) logic async_ack; | |
| (* dont_touch = "true" *) T async_data; | |
| if (CLEAR_ON_ASYNC_RESET) begin : gen_elaboration_assertion | |
| if (SYNC_STAGES < 3) | |
| $error("The clearable 2-phase CDC with async reset", | |
| "synchronization requires at least 3 synchronizer stages for the FIFO."); | |
| end else begin : gen_elaboration_assertion | |
| if (SYNC_STAGES < 2) begin : gen_elaboration_assertion | |
| $error("A minimum of 2 synchronizer stages is required for proper functionality."); | |
| end | |
| end | |
| cdc_2phase_src_clearable #( | |
| .T ( T ), | |
| .SYNC_STAGES ( SYNC_STAGES ) | |
| ) i_src ( | |
| .rst_ni ( src_rst_ni ), | |
| .clk_i ( src_clk_i ), | |
| .clear_i ( s_src_clear_req ), | |
| .data_i ( src_data_i ), | |
| .valid_i ( src_valid_i & !s_src_isolate_req ), | |
| .ready_o ( s_src_ready ), | |
| .async_req_o ( async_req ), | |
| .async_ack_i ( async_ack ), | |
| .async_data_o ( async_data ) | |
| ); | |
| assign src_ready_o = s_src_ready & !s_src_isolate_req; | |
| cdc_2phase_dst_clearable #( | |
| .T ( T ), | |
| .SYNC_STAGES ( SYNC_STAGES ) | |
| ) i_dst ( | |
| .rst_ni ( dst_rst_ni ), | |
| .clk_i ( dst_clk_i ), | |
| .clear_i ( s_dst_clear_req ), | |
| .data_o ( dst_data_o ), | |
| .valid_o ( s_dst_valid ), | |
| .ready_i ( dst_ready_i & !s_dst_isolate_req ), | |
| .async_req_i ( async_req ), | |
| .async_ack_o ( async_ack ), | |
| .async_data_i ( async_data ) | |
| ); | |
| assign dst_valid_o = s_dst_valid & !s_dst_isolate_req; | |
| cdc_reset_ctrlr #( | |
| .SYNC_STAGES(SYNC_STAGES-1) | |
| ) i_cdc_reset_ctrlr ( | |
| .a_clk_i ( src_clk_i ), | |
| .a_rst_ni ( src_rst_ni ), | |
| .a_clear_i ( src_clear_i ), | |
| .a_clear_o ( s_src_clear_req ), | |
| .a_clear_ack_i ( s_src_clear_ack_q ), | |
| .a_isolate_o ( s_src_isolate_req ), | |
| .a_isolate_ack_i ( s_src_isolate_ack_q ), | |
| .b_clk_i ( dst_clk_i ), | |
| .b_rst_ni ( dst_rst_ni ), | |
| .b_clear_i ( dst_clear_i ), | |
| .b_clear_o ( s_dst_clear_req ), | |
| .b_clear_ack_i ( s_dst_clear_ack_q ), | |
| .b_isolate_o ( s_dst_isolate_req ), | |
| .b_isolate_ack_i ( s_dst_isolate_ack_q ) | |
| ); | |
| always_ff @(posedge src_clk_i, negedge src_rst_ni) begin | |
| if (!src_rst_ni) begin | |
| s_src_isolate_ack_q <= 1'b0; | |
| s_src_clear_ack_q <= 1'b0; | |
| end else begin | |
| s_src_isolate_ack_q <= s_src_isolate_req; | |
| s_src_clear_ack_q <= s_src_clear_req; | |
| end | |
| end | |
| always_ff @(posedge dst_clk_i, negedge dst_rst_ni) begin | |
| if (!dst_rst_ni) begin | |
| s_dst_isolate_ack_q <= 1'b0; | |
| s_dst_clear_ack_q <= 1'b0; | |
| end else begin | |
| s_dst_isolate_ack_q <= s_dst_isolate_req; | |
| s_dst_clear_ack_q <= s_dst_clear_req; | |
| end | |
| end | |
| assign src_clear_pending_o = s_src_isolate_req; | |
| assign dst_clear_pending_o = s_dst_isolate_req; | |
| no_valid_i_during_clear_i: assert property (@(posedge src_clk_i) disable iff ((!src_rst_ni) !== '0) (src_clear_i |-> !src_valid_i)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "no_valid_i_during_clear_i", "", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_2phase_clearable.sv", 191); | |
| end | |
| endmodule | |
| module cdc_2phase_src_clearable #( | |
| parameter type T = logic, | |
| parameter int unsigned SYNC_STAGES = 2 | |
| ) ( | |
| input logic rst_ni, | |
| input logic clk_i, | |
| input logic clear_i, | |
| input T data_i, | |
| input logic valid_i, | |
| output logic ready_o, | |
| output logic async_req_o, | |
| input logic async_ack_i, | |
| output T async_data_o | |
| ); | |
| (* dont_touch = "true" *) | |
| logic req_src_d, req_src_q, ack_synced; | |
| (* dont_touch = "true" *) | |
| T data_src_d, data_src_q; | |
| sync #( | |
| .STAGES(SYNC_STAGES) | |
| ) i_sync( | |
| .clk_i, | |
| .rst_ni, | |
| .serial_i( async_ack_i ), | |
| .serial_o( ack_synced ) | |
| ); | |
| always_comb begin | |
| data_src_d = data_src_q; | |
| req_src_d = req_src_q; | |
| if (clear_i) begin | |
| req_src_d = 1'b0; | |
| end else if (valid_i && ready_o) begin | |
| req_src_d = ~req_src_q; | |
| data_src_d = data_i; | |
| end | |
| end | |
| always_ff @(posedge (clk_i)) begin | |
| data_src_q <= (data_src_d); | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| req_src_q <= 0; | |
| end else begin | |
| req_src_q <= req_src_d; | |
| end | |
| end | |
| assign ready_o = (req_src_q == ack_synced); | |
| assign async_req_o = req_src_q; | |
| assign async_data_o = data_src_q; | |
| no_clear_and_request: assume property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (clear_i |-> ~valid_i)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "no_clear_and_request", "No request allowed while clear_i is asserted.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/cdc_2phase_clearable.sv", 261); | |
| end | |
| endmodule | |
| module cdc_2phase_dst_clearable #( | |
| parameter type T = logic, | |
| parameter int unsigned SYNC_STAGES = 2 | |
| )( | |
| input logic rst_ni, | |
| input logic clk_i, | |
| input logic clear_i, | |
| output T data_o, | |
| output logic valid_o, | |
| input logic ready_i, | |
| input logic async_req_i, | |
| output logic async_ack_o, | |
| input T async_data_i | |
| ); | |
| (* dont_touch = "true" *) | |
| (* async_reg = "true" *) | |
| logic ack_dst_d, ack_dst_q, req_synced, req_synced_q1; | |
| (* dont_touch = "true" *) | |
| T data_dst_d, data_dst_q; | |
| sync #( | |
| .STAGES(SYNC_STAGES) | |
| ) i_sync( | |
| .clk_i, | |
| .rst_ni, | |
| .serial_i( async_req_i ), | |
| .serial_o( req_synced ) | |
| ); | |
| always_comb begin | |
| ack_dst_d = ack_dst_q; | |
| if (clear_i) begin | |
| ack_dst_d = 1'b0; | |
| end else if (valid_o && ready_i) begin | |
| ack_dst_d = ~ack_dst_q; | |
| end | |
| end | |
| always_comb begin | |
| data_dst_d = data_dst_q; | |
| if (req_synced != req_synced_q1 && !valid_o) begin | |
| data_dst_d = async_data_i; | |
| end | |
| end | |
| always_ff @(posedge (clk_i)) begin | |
| data_dst_q <= (data_dst_d); | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| ack_dst_q <= 0; | |
| req_synced_q1 <= 1'b0; | |
| end else begin | |
| ack_dst_q <= ack_dst_d; | |
| req_synced_q1 <= req_synced; | |
| end | |
| end | |
| assign valid_o = (ack_dst_q != req_synced_q1); | |
| assign data_o = data_dst_q; | |
| assign async_ack_o = ack_dst_q; | |
| endmodule | |
| /*verilator lint_on DECLFILENAME*/ | |
| `begin_keywords "1800-2023" | |
| module mem_to_banks_detailed #( | |
| parameter int unsigned AddrWidth = 32'd0, | |
| parameter int unsigned DataWidth = 32'd0, | |
| parameter int unsigned WUserWidth = 32'd0, | |
| parameter int unsigned RUserWidth = 32'd0, | |
| parameter int unsigned NumBanks = 32'd1, | |
| parameter bit HideStrb = 1'b0, | |
| parameter int unsigned MaxTrans = 32'd1, | |
| parameter int unsigned FifoDepth = 32'd1, | |
| parameter type wuser_t = logic [WUserWidth-1:0], | |
| localparam type addr_t = logic [AddrWidth-1:0], | |
| localparam type inp_data_t = logic [DataWidth-1:0], | |
| localparam type inp_strb_t = logic [DataWidth/8-1:0], | |
| localparam type inp_ruser_t = logic [NumBanks-1:0][RUserWidth-1:0], | |
| localparam type oup_data_t = logic [DataWidth/NumBanks-1:0], | |
| localparam type oup_strb_t = logic [DataWidth/NumBanks/8-1:0], | |
| localparam type oup_ruser_t = logic [RUserWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic req_i, | |
| output logic gnt_o, | |
| input addr_t addr_i, | |
| input inp_data_t wdata_i, | |
| input inp_strb_t strb_i, | |
| input wuser_t wuser_i, | |
| input logic we_i, | |
| output logic rvalid_o, | |
| output inp_data_t rdata_o, | |
| output inp_ruser_t ruser_o, | |
| output logic [NumBanks-1:0] bank_req_o, | |
| input logic [NumBanks-1:0] bank_gnt_i, | |
| output addr_t [NumBanks-1:0] bank_addr_o, | |
| output oup_data_t [NumBanks-1:0] bank_wdata_o, | |
| output oup_strb_t [NumBanks-1:0] bank_strb_o, | |
| output wuser_t [NumBanks-1:0] bank_wuser_o, | |
| output logic [NumBanks-1:0] bank_we_o, | |
| input logic [NumBanks-1:0] bank_rvalid_i, | |
| input oup_data_t [NumBanks-1:0] bank_rdata_i, | |
| input oup_ruser_t [NumBanks-1:0] bank_ruser_i | |
| ); | |
| localparam int unsigned DataBytes = $bits(inp_strb_t); | |
| localparam int unsigned BitsPerBank = $bits(oup_data_t); | |
| localparam int unsigned BytesPerBank = $bits(oup_strb_t); | |
| typedef struct packed { | |
| addr_t addr; | |
| oup_data_t wdata; | |
| oup_strb_t strb; | |
| wuser_t wuser; | |
| logic we; | |
| } req_t; | |
| logic req_valid; | |
| logic [NumBanks-1:0] req_ready, | |
| resp_valid, resp_ready; | |
| req_t [NumBanks-1:0] bank_req, | |
| bank_oup; | |
| logic [NumBanks-1:0] bank_req_internal, | |
| bank_gnt_internal, | |
| zero_strobe, | |
| dead_response, | |
| dead_response_unmasked; | |
| logic dead_write_fifo_full, | |
| dead_write_fifo_empty; | |
| function automatic addr_t align_addr(input addr_t addr); | |
| return (addr >> $clog2(DataBytes)) << $clog2(DataBytes); | |
| endfunction | |
| assign req_valid = req_i & gnt_o; | |
| for (genvar i = 0; unsigned'(i) < NumBanks; i++) begin : gen_reqs | |
| assign bank_req[i].addr = align_addr(addr_i) + i * BytesPerBank; | |
| assign bank_req[i].wdata = wdata_i[i*BitsPerBank+:BitsPerBank]; | |
| assign bank_req[i].strb = strb_i[i*BytesPerBank+:BytesPerBank]; | |
| assign bank_req[i].wuser = wuser_i; | |
| assign bank_req[i].we = we_i; | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b1 ), | |
| .DATA_WIDTH ( $bits(req_t) ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( req_t ) | |
| ) i_ft_reg ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .usage_o (), | |
| .data_i ( bank_req[i] ), | |
| .valid_i ( req_valid ), | |
| .ready_o ( req_ready[i] ), | |
| .data_o ( bank_oup[i] ), | |
| .valid_o ( bank_req_internal[i] ), | |
| .ready_i ( bank_gnt_internal[i] ) | |
| ); | |
| assign bank_addr_o[i] = bank_oup[i].addr; | |
| assign bank_wdata_o[i] = bank_oup[i].wdata; | |
| assign bank_strb_o[i] = bank_oup[i].strb; | |
| assign bank_wuser_o[i] = bank_oup[i].wuser; | |
| assign bank_we_o[i] = bank_oup[i].we; | |
| assign zero_strobe[i] = (bank_req[i].strb == '0); | |
| if (HideStrb) begin : gen_hide_strb | |
| assign bank_req_o[i] = (bank_oup[i].we && (bank_oup[i].strb == '0)) ? | |
| 1'b0 : bank_req_internal[i]; | |
| assign bank_gnt_internal[i] = (bank_oup[i].we && (bank_oup[i].strb == '0)) ? | |
| 1'b1 : bank_gnt_i[i]; | |
| end else begin : gen_legacy_strb | |
| assign bank_req_o[i] = bank_req_internal[i]; | |
| assign bank_gnt_internal[i] = bank_gnt_i[i]; | |
| end | |
| end | |
| assign gnt_o = (&req_ready) & (&resp_ready) & !dead_write_fifo_full; | |
| if (HideStrb) begin : gen_dead_write_fifo | |
| fifo_v3 #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DEPTH ( MaxTrans+1 ), | |
| .DATA_WIDTH ( NumBanks ) | |
| ) i_dead_write_fifo ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .full_o ( dead_write_fifo_full ), | |
| .empty_o ( dead_write_fifo_empty ), | |
| .usage_o (), | |
| .data_i ( {NumBanks{we_i}} & zero_strobe ), | |
| .push_i ( req_i & gnt_o ), | |
| .data_o ( dead_response_unmasked ), | |
| .pop_i ( rvalid_o ) | |
| ); | |
| assign dead_response = dead_response_unmasked & {NumBanks{~dead_write_fifo_empty}}; | |
| end else begin : gen_no_dead_write_fifo | |
| assign dead_response_unmasked = '0; | |
| assign dead_response = '0; | |
| assign dead_write_fifo_full = 1'b0; | |
| assign dead_write_fifo_empty = 1'b1; | |
| end | |
| for (genvar i = 0; unsigned'(i) < NumBanks; i++) begin : gen_resp_regs | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b1 ), | |
| .DATA_WIDTH ( $bits(oup_data_t) + $bits(oup_ruser_t) ), | |
| .DEPTH ( FifoDepth ) | |
| ) i_ft_reg ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .usage_o (), | |
| .data_i ( {bank_rdata_i[i], bank_ruser_i[i]} ), | |
| .valid_i ( bank_rvalid_i[i] ), | |
| .ready_o ( resp_ready[i] ), | |
| .data_o ( {rdata_o[i*BitsPerBank+:BitsPerBank], ruser_o[i]} ), | |
| .valid_o ( resp_valid[i] ), | |
| .ready_i ( rvalid_o & !dead_response[i] ) | |
| ); | |
| end | |
| assign rvalid_o = &(resp_valid | dead_response); | |
| initial begin | |
| datawidth_not_power_of_2: assume (DataWidth != 0 && 2**$clog2(DataWidth) == DataWidth) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "datawidth_not_power_of_2", "Data width must be a power of two!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/mem_to_banks_detailed.sv", 226); | |
| end | |
| datawidth_not_divisible_by_banks: assume (DataWidth % NumBanks == 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "datawidth_not_divisible_by_banks", "Data width must be evenly divisible over banks!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/mem_to_banks_detailed.sv", 228); | |
| end | |
| bank_datawidth_not_divisible_by_8: assume ((DataWidth / NumBanks) % 8 == 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "bank_datawidth_not_divisible_by_8", "Data width of each bank must be divisible into 8-bit bytes!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/mem_to_banks_detailed.sv", 230); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_arbiter #( | |
| parameter type DATA_T = logic, | |
| parameter integer N_INP = -1, | |
| parameter ARBITER = "rr" | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input DATA_T [N_INP-1:0] inp_data_i, | |
| input logic [N_INP-1:0] inp_valid_i, | |
| output logic [N_INP-1:0] inp_ready_o, | |
| output DATA_T oup_data_o, | |
| output logic oup_valid_o, | |
| input logic oup_ready_i | |
| ); | |
| stream_arbiter_flushable #( | |
| .DATA_T (DATA_T), | |
| .N_INP (N_INP), | |
| .ARBITER (ARBITER) | |
| ) i_arb ( | |
| .clk_i (clk_i), | |
| .rst_ni (rst_ni), | |
| .flush_i (1'b0), | |
| .inp_data_i (inp_data_i), | |
| .inp_valid_i (inp_valid_i), | |
| .inp_ready_o (inp_ready_o), | |
| .oup_data_o (oup_data_o), | |
| .oup_valid_o (oup_valid_o), | |
| .oup_ready_i (oup_ready_i) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_omega_net #( | |
| parameter int unsigned NumInp = 32'd0, | |
| parameter int unsigned NumOut = 32'd0, | |
| parameter int unsigned Radix = 32'd2, | |
| parameter int unsigned DataWidth = 32'd1, | |
| parameter type payload_t = logic [DataWidth-1:0], | |
| parameter bit SpillReg = 1'b0, | |
| parameter int unsigned ExtPrio = 1'b0, | |
| parameter int unsigned AxiVldRdy = 1'b1, | |
| parameter int unsigned LockIn = 1'b1, | |
| parameter payload_t AxiVldMask = '1, | |
| parameter int unsigned SelWidth = (NumOut > 32'd1) ? unsigned'($clog2(NumOut)) : 32'd1, | |
| parameter type sel_oup_t = logic[SelWidth-1:0], | |
| parameter int unsigned IdxWidth = (NumInp > 32'd1) ? unsigned'($clog2(NumInp)) : 32'd1, | |
| parameter type idx_inp_t = logic[IdxWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input idx_inp_t [NumOut-1:0] rr_i, | |
| input payload_t [NumInp-1:0] data_i, | |
| input sel_oup_t [NumInp-1:0] sel_i, | |
| input logic [NumInp-1:0] valid_i, | |
| output logic [NumInp-1:0] ready_o, | |
| output payload_t [NumOut-1:0] data_o, | |
| output idx_inp_t [NumOut-1:0] idx_o, | |
| output logic [NumOut-1:0] valid_o, | |
| input logic [NumOut-1:0] ready_i | |
| ); | |
| if (NumInp <= Radix && NumOut <= Radix) begin : gen_degenerate_omega_net | |
| stream_xbar #( | |
| .NumInp ( NumInp ), | |
| .NumOut ( NumOut ), | |
| .payload_t ( payload_t ), | |
| .OutSpillReg ( SpillReg ), | |
| .ExtPrio ( ExtPrio ), | |
| .AxiVldRdy ( AxiVldRdy ), | |
| .LockIn ( LockIn ) | |
| ) i_stream_xbar ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .rr_i ( rr_i ), | |
| .data_i ( data_i ), | |
| .sel_i ( sel_i ), | |
| .valid_i ( valid_i ), | |
| .ready_o ( ready_o ), | |
| .data_o ( data_o ), | |
| .idx_o ( idx_o ), | |
| .valid_o ( valid_o ), | |
| .ready_i ( ready_i ) | |
| ); | |
| end else begin : gen_omega_net | |
| localparam int unsigned NumLanes = (NumOut > NumInp) ? | |
| unsigned'(Radix**(cf_math_pkg::ceil_div($clog2(NumOut), $clog2(Radix)))) : | |
| unsigned'(Radix**(cf_math_pkg::ceil_div($clog2(NumInp), $clog2(Radix)))); | |
| localparam int unsigned NumLevels = unsigned'(($clog2(NumLanes)+$clog2(Radix)-1)/$clog2(Radix)); | |
| localparam int unsigned NumRouters = NumLanes / Radix; | |
| typedef logic [$clog2(NumLanes)-1:0] sel_dst_t; | |
| localparam int unsigned SelW = unsigned'($clog2(Radix)); | |
| initial begin : proc_selw | |
| $display("SelW is: %0d", SelW); | |
| $display("SelDstW is: %0d", $bits(sel_dst_t)); | |
| end | |
| typedef logic [SelW-1:0] sel_t; | |
| typedef struct packed { | |
| sel_dst_t sel_oup; | |
| payload_t payload; | |
| idx_inp_t idx_inp; | |
| } omega_data_t; | |
| omega_data_t [NumLevels-1:0][NumRouters-1:0][Radix-1:0] inp_router_data; | |
| logic [NumLevels-1:0][NumRouters-1:0][Radix-1:0] inp_router_valid, inp_router_ready; | |
| omega_data_t [NumLevels-1:0][NumRouters-1:0][Radix-1:0] out_router_data; | |
| logic [NumLevels-1:0][NumRouters-1:0][Radix-1:0] out_router_valid, out_router_ready; | |
| for (genvar i = 0; unsigned'(i) < NumLevels-1; i++) begin : gen_shuffle_levels | |
| for (genvar j = 0; unsigned'(j) < NumRouters; j++) begin : gen_shuffle_routers | |
| for (genvar k = 0; unsigned'(k) < Radix; k++) begin : gen_shuffle_radix | |
| localparam int unsigned IdxLane = Radix * j + k; | |
| assign inp_router_data[i+1][IdxLane%NumRouters][IdxLane/NumRouters] = | |
| out_router_data[i][j][k]; | |
| assign inp_router_valid[i+1][IdxLane%NumRouters][IdxLane/NumRouters] = | |
| out_router_valid[i][j][k]; | |
| assign out_router_ready[i][j][k] = | |
| inp_router_ready[i+1][IdxLane%NumRouters][IdxLane/NumRouters]; | |
| if (i == 0) begin : gen_shuffle_inp | |
| if ((NumLanes-IdxLane) <= NumInp) begin : gen_inp_ports | |
| localparam int unsigned IdxInp = NumLanes - IdxLane - 32'd1; | |
| assign inp_router_data[0][IdxLane%NumRouters][IdxLane/NumRouters] = '{ | |
| sel_oup: sel_dst_t'(sel_i[IdxInp]), | |
| payload: data_i[IdxInp], | |
| idx_inp: idx_inp_t'(IdxInp) | |
| }; | |
| assign inp_router_valid[0][IdxLane%NumRouters][IdxLane/NumRouters] = valid_i[IdxInp]; | |
| assign ready_o[IdxInp] = inp_router_ready[0][IdxLane%NumRouters][IdxLane/NumRouters]; | |
| end else begin : gen_tie_off | |
| assign inp_router_data[0][IdxLane%NumRouters][IdxLane/NumRouters] = '{ default: '0}; | |
| assign inp_router_valid[0][IdxLane%NumRouters][IdxLane/NumRouters] = 1'b0; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| for (genvar i = 0; unsigned'(i) < NumLevels; i++) begin : gen_router_levels | |
| for (genvar j = 0; unsigned'(j) < NumRouters; j++) begin : gen_routers | |
| sel_t [Radix-1:0] sel_router; | |
| for (genvar k = 0; unsigned'(k) < Radix; k++) begin : gen_router_sel | |
| assign sel_router[k] = inp_router_data[i][j][k].sel_oup[SelW*(NumLevels-i-1)+:SelW]; | |
| end | |
| stream_xbar #( | |
| .NumInp ( Radix ), | |
| .NumOut ( Radix ), | |
| .payload_t ( omega_data_t ), | |
| .OutSpillReg ( SpillReg ), | |
| .ExtPrio ( 1'b0 ), | |
| .AxiVldRdy ( AxiVldRdy ), | |
| .LockIn ( LockIn ) | |
| ) i_stream_xbar ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .rr_i ( '0 ), | |
| .data_i ( inp_router_data[i][j] ), | |
| .sel_i ( sel_router ), | |
| .valid_i ( inp_router_valid[i][j] ), | |
| .ready_o ( inp_router_ready[i][j] ), | |
| .data_o ( out_router_data[i][j] ), | |
| .idx_o ( ), | |
| .valid_o ( out_router_valid[i][j] ), | |
| .ready_i ( out_router_ready[i][j] ) | |
| ); | |
| end | |
| end | |
| for (genvar i = 0; unsigned'(i) < NumLanes; i++) begin : gen_outputs | |
| if (i < NumOut) begin : gen_connect | |
| assign data_o[i] = out_router_data[NumLevels-1][i/Radix][i%Radix].payload; | |
| assign idx_o[i] = out_router_data[NumLevels-1][i/Radix][i%Radix].idx_inp; | |
| assign valid_o[i] = out_router_valid[NumLevels-1][i/Radix][i%Radix]; | |
| assign out_router_ready[NumLevels-1][i/Radix][i%Radix] = ready_i[i]; | |
| end else begin : gen_tie_off | |
| assign out_router_ready[NumLevels-1][i/Radix][i%Radix] = 1'b0; | |
| end | |
| end | |
| initial begin : proc_debug_print | |
| $display("NumInp: %0d", NumInp); | |
| $display("NumOut: %0d", NumOut); | |
| $display("Radix: %0d", Radix); | |
| $display("NumLanes: %0d", NumLanes); | |
| $display("NumLevels: %0d", NumLevels); | |
| $display("NumRouters: %0d", NumRouters); | |
| end | |
| for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_sel_assertions | |
| non_existing_output: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_i[i] |-> sel_i[i] < NumOut)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "non_existing_output", "Non-existing output is selected!", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 272); | |
| end | |
| end | |
| if (AxiVldRdy) begin : gen_handshake_assertions | |
| for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_inp_assertions | |
| input_data_unstable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_i[i] && !ready_o[i] |=> $stable(data_i[i] & AxiVldMask))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "input_data_unstable", $sformatf("data_i is unstable at input: %0d", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 278); | |
| end | |
| input_sel_unstable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_i[i] && !ready_o[i] |=> $stable(sel_i[i]))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "input_sel_unstable", $sformatf("sel_i is unstable at input: %0d", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 280); | |
| end | |
| input_valid_taken: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_i[i] && !ready_o[i] |=> valid_i[i])) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "input_valid_taken", $sformatf("valid_i at input %0d has been taken away without a ready.", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 282); | |
| end | |
| end | |
| for (genvar i = 0; unsigned'(i) < NumOut; i++) begin : gen_out_assertions | |
| output_data_unstable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_o[i] && !ready_i[i] |=> $stable(data_o[i] & AxiVldMask))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "output_data_unstable", $sformatf("data_o is unstable at output: %0d Check that parameter LockIn is set.", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 288); | |
| end | |
| output_idx_unstable: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_o[i] && !ready_i[i] |=> $stable(idx_o[i]))) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "output_idx_unstable", $sformatf("idx_o is unstable at output: %0d Check that parameter LockIn is set.", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 292); | |
| end | |
| output_valid_taken: assert property (@(posedge clk_i) disable iff ((!rst_ni) !== '0) (valid_o[i] && !ready_i[i] |=> valid_o[i])) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "output_valid_taken", $sformatf("valid_o at output %0d has been taken away without a ready.", i), "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 294); | |
| end | |
| end | |
| end | |
| initial begin | |
| radix_not_power_of_2: assert ((2**$clog2(Radix) == Radix) && (Radix > 32'd1)) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "radix_not_power_of_2", "Radix is not power of two.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 299); | |
| end | |
| end | |
| initial begin | |
| num_routers_not_power_of_2: assert (2**$clog2(NumRouters) == NumRouters) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "num_routers_not_power_of_2", "NumRouters is not power of two.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 301); | |
| end | |
| end | |
| initial begin | |
| bit_slicing_broken: assert ($clog2(NumLanes) % SelW == 0) | |
| else begin | |
| $error("[ASSERT FAILED] [%m] %s: %s (%s:%0d)", "bit_slicing_broken", "Bit slicing of the internal selection signal is broken.", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/src/stream_omega_net.sv", 303); | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module mem_to_banks #( | |
| parameter int unsigned AddrWidth = 32'd0, | |
| parameter int unsigned DataWidth = 32'd0, | |
| parameter int unsigned AtopWidth = 32'd0, | |
| parameter int unsigned NumBanks = 32'd1, | |
| parameter bit HideStrb = 1'b0, | |
| parameter int unsigned MaxTrans = 32'd1, | |
| parameter int unsigned FifoDepth = 32'd1, | |
| parameter type atop_t = logic [AtopWidth-1:0], | |
| localparam type addr_t = logic [AddrWidth-1:0], | |
| localparam type inp_data_t = logic [DataWidth-1:0], | |
| localparam type inp_strb_t = logic [DataWidth/8-1:0], | |
| localparam type oup_data_t = logic [DataWidth/NumBanks-1:0], | |
| localparam type oup_strb_t = logic [DataWidth/NumBanks/8-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic req_i, | |
| output logic gnt_o, | |
| input addr_t addr_i, | |
| input inp_data_t wdata_i, | |
| input inp_strb_t strb_i, | |
| input atop_t atop_i, | |
| input logic we_i, | |
| output logic rvalid_o, | |
| output inp_data_t rdata_o, | |
| output logic [NumBanks-1:0] bank_req_o, | |
| input logic [NumBanks-1:0] bank_gnt_i, | |
| output addr_t [NumBanks-1:0] bank_addr_o, | |
| output oup_data_t [NumBanks-1:0] bank_wdata_o, | |
| output oup_strb_t [NumBanks-1:0] bank_strb_o, | |
| output atop_t [NumBanks-1:0] bank_atop_o, | |
| output logic [NumBanks-1:0] bank_we_o, | |
| input logic [NumBanks-1:0] bank_rvalid_i, | |
| input oup_data_t [NumBanks-1:0] bank_rdata_i | |
| ); | |
| mem_to_banks_detailed #( | |
| .AddrWidth ( AddrWidth ), | |
| .DataWidth ( DataWidth ), | |
| .WUserWidth ( AtopWidth ), | |
| .RUserWidth ( 1 ), | |
| .NumBanks ( NumBanks ), | |
| .HideStrb ( HideStrb ), | |
| .MaxTrans ( MaxTrans ), | |
| .FifoDepth ( FifoDepth ), | |
| .wuser_t ( atop_t ) | |
| ) i_mem_to_banks_detailed ( | |
| .clk_i, | |
| .rst_ni, | |
| .req_i, | |
| .gnt_o, | |
| .addr_i, | |
| .wdata_i, | |
| .strb_i, | |
| .wuser_i ( atop_i ), | |
| .we_i, | |
| .rvalid_o, | |
| .rdata_o, | |
| .ruser_o (), | |
| .bank_req_o, | |
| .bank_gnt_i, | |
| .bank_addr_o, | |
| .bank_wdata_o, | |
| .bank_strb_o, | |
| .bank_wuser_o ( bank_atop_o ), | |
| .bank_we_o, | |
| .bank_rvalid_i, | |
| .bank_rdata_i, | |
| .bank_ruser_i ('0) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module addr_decode_tb; | |
| localparam int unsigned NoIndices = 2; | |
| localparam int unsigned NoRules = 3; | |
| localparam int unsigned AddrWidth = 12; | |
| typedef logic [AddrWidth-1:0] addr_t; | |
| typedef logic [$clog2(NoIndices)-1:0] idx_t; | |
| typedef struct packed { | |
| int unsigned idx; | |
| addr_t start_addr; | |
| addr_t end_addr; | |
| } tb_rule_t; | |
| localparam tb_rule_t [NoRules-1:0] map_0 = '{ | |
| '{idx: 32'd0, start_addr: 12'h000, end_addr: 12'h010}, | |
| '{idx: 32'd1, start_addr: 12'h010, end_addr: 12'h020}, | |
| '{idx: 32'd0, start_addr: 12'hF00, end_addr: 12'hFFF} | |
| }; | |
| localparam tb_rule_t [NoRules-1:0] map_1 = '{ | |
| '{idx: 32'd0, start_addr: 12'h000, end_addr: 12'h010}, | |
| '{idx: 32'd1, start_addr: 12'h00D, end_addr: 12'h020}, | |
| '{idx: 32'd1, start_addr: 12'h100, end_addr: 12'hFFF} | |
| }; | |
| addr_t addr; | |
| tb_rule_t [NoRules-1:0] addr_map; | |
| idx_t idx; | |
| logic dec_valid, dec_error; | |
| logic en_default_idx; | |
| idx_t default_idx; | |
| longint unsigned passed_checks = 0; | |
| longint unsigned failed_checks = 0; | |
| initial begin : stimulus | |
| passed_checks <= 0; | |
| failed_checks <= 0; | |
| addr_map <= map_0; | |
| en_default_idx <= 1'b0; | |
| default_idx <= idx_t'(1); | |
| #500; | |
| $info("Start address application"); | |
| for (int i = 0; i < 2**AddrWidth; i++) begin | |
| addr <= addr_t'(i); | |
| #1; | |
| end | |
| $info("Change addr map to an overlapping one expect warning"); | |
| addr_map <= map_1; | |
| #100; | |
| $info("Change addr map back and enable default decode to idx 1"); | |
| addr_map <= map_0; | |
| en_default_idx <= 1'b1; | |
| #100; | |
| for (int i = 0; i < 2**AddrWidth; i++) begin | |
| addr <= addr_t'(i); | |
| #1; | |
| end | |
| #500 | |
| $info("Finished Simulation"); | |
| $display("Passed: %d", passed_checks); | |
| $display("Failed: %d", failed_checks); | |
| $stop(); | |
| end | |
| always @(addr) #0 begin : proc_check_decode | |
| for (int unsigned i = 0; i < NoRules; i++) begin | |
| if ((addr >= addr_map[i].start_addr) && (addr < addr_map[i].end_addr )) begin | |
| check_decode: assert (idx == addr_map[i].idx) passed_checks++; else begin | |
| failed_checks++; | |
| $warning("Decoder did not decode correctly."); | |
| end | |
| check_valid: assert (dec_valid == 1'b1 && dec_error == 1'b0) passed_checks++; else begin | |
| failed_checks++; | |
| $warning("Unexpected decode flag on assumed valid decode."); | |
| end | |
| end else begin | |
| if (dec_valid == 1'b0) begin | |
| if (en_default_idx) begin | |
| check_default: assert (default_idx == idx) passed_checks++; else begin | |
| failed_checks++; | |
| $warning("Enabled default index, however wrong default decoding."); | |
| end | |
| check_flags: assert (dec_error == 1'b0) passed_checks++; else begin | |
| failed_checks++; | |
| $warning("Unexpected decode flags on default decode enabled."); | |
| end | |
| end else begin | |
| check_error: assert (dec_error == 1'b1) passed_checks++; else begin | |
| failed_checks++; | |
| $warning("Unexpected decode flags on assumed decode error."); | |
| end | |
| end | |
| end | |
| end | |
| end | |
| end | |
| addr_decode #( | |
| .NoIndices ( NoIndices ), | |
| .NoRules ( NoRules ), | |
| .addr_t ( addr_t ), | |
| .rule_t ( tb_rule_t ) | |
| ) i_addr_decode_dut ( | |
| .addr_i ( addr ), | |
| .addr_map_i ( addr_map ), | |
| .idx_o ( idx ), | |
| .dec_valid_o ( dec_valid ), | |
| .dec_error_o ( dec_error ), | |
| .en_default_idx_i( en_default_idx ), | |
| .default_idx_i ( default_idx ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cb_filter_tb; | |
| localparam time TCycle = 10ns; | |
| localparam time TAppli = 2ns; | |
| localparam time TTest = 8ns; | |
| localparam int unsigned RunCycles = 10000000; | |
| localparam int unsigned NoHashes = 32'd3; | |
| localparam int unsigned HashWidth = 32'd6; | |
| localparam int unsigned HashRounds = 32'd1; | |
| localparam int unsigned DataWidth = 32'd11; | |
| localparam int unsigned BucketWidth = 32'd3; | |
| typedef logic [DataWidth-1:0] data_t; | |
| localparam cb_filter_pkg::cb_seed_t [NoHashes-1:0] Seeds = '{ | |
| '{PermuteSeed: 32'd299034753, XorSeed: 32'd4094834 }, | |
| '{PermuteSeed: 32'd19921030, XorSeed: 32'd995713 }, | |
| '{PermuteSeed: 32'd294388, XorSeed: 32'd65146511} | |
| }; | |
| logic control_array [*]; | |
| int unsigned max_items; | |
| int unsigned min_items; | |
| longint unsigned no_tests; | |
| longint unsigned no_positives; | |
| longint unsigned no_false_positives; | |
| longint unsigned no_negatives; | |
| longint unsigned no_false_negatives; | |
| logic clk; | |
| logic rst_n; | |
| logic sim_done; | |
| data_t look_data; | |
| logic look_valid; | |
| data_t incr_data; | |
| logic incr_valid; | |
| data_t decr_data; | |
| logic decr_valid; | |
| logic filter_clear; | |
| logic [HashWidth-1:0] filter_usage; | |
| logic filter_full, filter_empty, filter_error; | |
| clk_rst_gen #( | |
| .ClkPeriod ( TCycle ), | |
| .RstClkCycles ( 5 ) | |
| ) i_clk_gen ( | |
| .clk_o ( clk ), | |
| .rst_no ( rst_n ) | |
| ); | |
| initial begin : stimulus | |
| sim_done = 1'b0; | |
| no_tests = 64'd0; | |
| no_positives = 64'd0; | |
| no_false_positives = 64'd0; | |
| no_negatives = 64'd0; | |
| no_false_negatives = 64'd0; | |
| init_signals(); | |
| fork | |
| begin | |
| max_items = 10; | |
| min_items = 3; | |
| @(posedge rst_n); | |
| repeat (RunCycles) @(posedge clk); | |
| sim_done = 1'b1; | |
| end | |
| begin | |
| @(posedge rst_n); | |
| run_lookup(sim_done); | |
| end | |
| begin | |
| @(posedge rst_n); | |
| run_increment(sim_done, decr_valid); | |
| end | |
| begin | |
| @(posedge rst_n); | |
| run_decrement(sim_done); | |
| end | |
| join | |
| print_result(no_tests, no_positives, no_false_positives, no_negatives, no_false_negatives); | |
| empty_filter(); | |
| $stop(); | |
| end | |
| task cycle_start(); | |
| #TTest; | |
| endtask : cycle_start | |
| task cycle_end(); | |
| @(posedge clk); | |
| endtask : cycle_end | |
| task reset_filter(); | |
| filter_clear <= #TAppli '1; | |
| cycle_end(); | |
| filter_clear <= #TAppli '0; | |
| endtask : reset_filter | |
| task init_signals(); | |
| look_data <= #TAppli '0; | |
| incr_data <= #TAppli '0; | |
| incr_valid <= #TAppli '0; | |
| decr_data <= #TAppli '0; | |
| decr_valid <= #TAppli '0; | |
| filter_clear <= #TAppli '0; | |
| endtask : init_signals | |
| task automatic run_lookup(ref logic sim_done); | |
| while (!sim_done) begin | |
| logic [DataWidth-1:0] lookup = $urandom_range(0,2**DataWidth-1);; | |
| rand_wait(0,6); | |
| look_data <= #TAppli lookup; | |
| cycle_start(); | |
| no_tests++; | |
| if(control_array.exists(lookup)) begin | |
| if(!look_valid) begin | |
| $warning(1, "Had a false negative!!!\nIndex: %d", lookup); | |
| no_false_negatives++; | |
| end else begin | |
| no_positives++; | |
| end | |
| end else begin | |
| if(look_valid) begin | |
| no_false_positives++; | |
| end else begin | |
| no_negatives++; | |
| end | |
| end | |
| cycle_end(); | |
| end | |
| endtask : run_lookup | |
| task automatic run_increment(ref logic sim_done, ref logic decr_valid); | |
| while (!sim_done) begin | |
| logic [DataWidth-1:0] data = $urandom_range(0,2**DataWidth-1); | |
| if(!control_array.exists(data)) begin | |
| rand_wait(0,5); | |
| incr_data <= #TAppli data; | |
| while (filter_full | (control_array.num() > max_items)) | |
| begin if (sim_done | decr_valid) break; cycle_end(); end | |
| incr_valid <= #TAppli 1'b1; | |
| cycle_end(); | |
| control_array[data] = 1'b1; | |
| incr_data <= #TAppli '0; | |
| incr_valid <= #TAppli '0; | |
| end else begin | |
| cycle_end(); | |
| end | |
| end | |
| endtask : run_increment | |
| task automatic run_decrement(ref logic sim_done); | |
| int unsigned nb_tryes = 0; | |
| while (!sim_done) begin | |
| logic [DataWidth-1:0] data = $urandom_range(0,2**DataWidth-1);; | |
| if(control_array.exists(data)) begin | |
| if(control_array.num() > min_items) begin | |
| rand_wait(0,5); | |
| decr_data <= #TAppli data; | |
| decr_valid <= #TAppli 1'b1; | |
| cycle_start(); | |
| control_array.delete(data); | |
| cycle_end(); | |
| decr_data <= #TAppli '0; | |
| decr_valid <= #TAppli 1'b0; | |
| end else begin | |
| cycle_end(); | |
| end | |
| end else begin | |
| if(nb_tryes < 100) begin | |
| nb_tryes++; | |
| end else begin | |
| nb_tryes = 0; | |
| cycle_end(); | |
| end | |
| end | |
| end | |
| endtask : run_decrement | |
| task empty_filter(); | |
| rand_wait(10,15); | |
| for (int unsigned i = 0; i < 2**DataWidth; i++) begin | |
| if(control_array.exists(i)) begin | |
| decr_data <= #TAppli i; | |
| decr_valid <= #TAppli 1'b1; | |
| cycle_start(); | |
| control_array.delete(i); | |
| cycle_end(); | |
| end | |
| end | |
| decr_data <= #TAppli '0; | |
| decr_valid <= #TAppli 1'b0; | |
| cycle_start(); | |
| cycle_end(); | |
| $display("Filter empty is: %b", filter_empty); | |
| endtask : empty_filter | |
| task print_result(input longint unsigned n_test, n_pos, n_f_pos, n_neg, n_f_neg); | |
| $info( "######################################################"); | |
| if (n_f_neg == 64'h0) begin | |
| $display("***SUCCESS***"); | |
| end else begin | |
| $display("!!!FAILED!!!"); | |
| end | |
| $display("Finished Tests"); | |
| $display("NO Testes: %d", n_test); | |
| $display("NO Positive: %d", n_pos); | |
| $display("NO False Pos: %d", n_f_pos); | |
| $display("NO Negatives: %d", n_neg); | |
| $display("NO False Neg: %d <--- Success if this is 0!", n_f_neg); | |
| $display("######################################################"); | |
| endtask : print_result | |
| task automatic rand_wait(input int unsigned min, max); | |
| int unsigned rand_success, cycles; | |
| rand_success = std::randomize(cycles) with { | |
| cycles >= min; | |
| cycles <= max; | |
| }; | |
| assert (rand_success) else $error("Failed to randomize wait cycles!"); | |
| repeat (cycles) @(posedge clk); | |
| endtask : rand_wait | |
| cb_filter #( | |
| .KHashes ( NoHashes ), | |
| .HashWidth ( HashWidth ), | |
| .HashRounds ( HashRounds ), | |
| .InpWidth ( DataWidth ), | |
| .BucketWidth ( BucketWidth ), | |
| .Seeds ( Seeds ) | |
| ) i_dut ( | |
| .clk_i ( clk ), | |
| .rst_ni ( rst_n ), | |
| .look_data_i ( look_data ), | |
| .look_valid_o ( look_valid ), | |
| .incr_data_i ( incr_data ), | |
| .incr_valid_i ( incr_valid ), | |
| .decr_data_i ( decr_data ), | |
| .decr_valid_i ( decr_valid ), | |
| .filter_clear_i ( filter_clear ), | |
| .filter_usage_o ( filter_usage ), | |
| .filter_full_o ( filter_full ), | |
| .filter_empty_o ( filter_empty ), | |
| .filter_error_o ( filter_error ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cdc_2phase_tb; | |
| parameter int UNTIL = 100000; | |
| parameter bit INJECT_DELAYS = 1; | |
| parameter bit POST_SYNTHESIS = 0; | |
| time tck_src = 10ns; | |
| time tck_dst = 10ns; | |
| bit src_done = 0; | |
| bit dst_done = 0; | |
| bit done; | |
| assign done = src_done & dst_done; | |
| logic src_rst_ni = 1; | |
| logic src_clk_i = 0; | |
| logic [31:0] src_data_i = 0; | |
| logic src_valid_i = 0; | |
| logic src_ready_o; | |
| logic dst_rst_ni = 1; | |
| logic dst_clk_i = 0; | |
| logic [31:0] dst_data_o; | |
| logic dst_valid_o; | |
| logic dst_ready_i = 0; | |
| if (POST_SYNTHESIS) begin : g_dut | |
| cdc_2phase_synth i_dut (.*); | |
| end else if (INJECT_DELAYS) begin : g_dut | |
| cdc_2phase_tb_delay_injector #(0.8ns) i_dut (.*); | |
| end else begin : g_dut | |
| cdc_2phase #(logic [31:0]) i_dut (.*); | |
| end | |
| mailbox #(int) dst_mbox = new(); | |
| int num_sent = 0; | |
| int num_received = 0; | |
| int num_failed = 0; | |
| initial begin | |
| static int num_items, num_clks; | |
| num_items = 10; | |
| num_clks = 0; | |
| #10ns; | |
| src_rst_ni = 0; | |
| #10ns; | |
| src_rst_ni = 1; | |
| #10ns; | |
| while (!done) begin | |
| src_clk_i = 1; | |
| #(tck_src/2); | |
| src_clk_i = 0; | |
| #(tck_src/2); | |
| num_clks++; | |
| if (num_sent >= num_items && num_clks > 10) begin | |
| num_items = num_sent + 10; | |
| num_clks = 0; | |
| tck_src = $urandom_range(1000, 10000) * 1ps; | |
| assert(tck_src > 0); | |
| end | |
| end | |
| end | |
| initial begin | |
| static int num_items, num_clks; | |
| num_items = 10; | |
| num_clks = 0; | |
| #10ns; | |
| dst_rst_ni = 0; | |
| #10ns; | |
| dst_rst_ni = 1; | |
| #10ns; | |
| while (!done) begin | |
| dst_clk_i = 1; | |
| #(tck_dst/2); | |
| dst_clk_i = 0; | |
| #(tck_dst/2); | |
| num_clks++; | |
| if (num_received >= num_items && num_clks > 10) begin | |
| num_items = num_received + 10; | |
| num_clks = 0; | |
| tck_dst = $urandom_range(1000, 10000) * 1ps; | |
| assert(tck_dst > 0); | |
| end | |
| end | |
| end | |
| task src_cycle_start; | |
| #(tck_src*0.8); | |
| endtask | |
| task src_cycle_end; | |
| @(posedge src_clk_i); | |
| endtask | |
| initial begin | |
| @(negedge src_rst_ni); | |
| @(posedge src_rst_ni); | |
| repeat(3) @(posedge src_clk_i); | |
| for (int i = 0; i < UNTIL; i++) begin | |
| static integer stimulus; | |
| stimulus = $random(); | |
| src_data_i <= #(tck_src*0.2) stimulus; | |
| src_valid_i <= #(tck_src*0.2) 1; | |
| dst_mbox.put(stimulus); | |
| num_sent++; | |
| src_cycle_start(); | |
| while (!src_ready_o) begin | |
| src_cycle_end(); | |
| src_cycle_start(); | |
| end | |
| src_cycle_end(); | |
| src_valid_i <= #(tck_src*0.2) 0; | |
| end | |
| src_done = 1; | |
| end | |
| task dst_cycle_start; | |
| #(tck_dst*0.8); | |
| endtask | |
| task dst_cycle_end; | |
| @(posedge dst_clk_i); | |
| endtask | |
| initial begin | |
| @(negedge dst_rst_ni); | |
| @(posedge dst_rst_ni); | |
| repeat(3) @(posedge dst_clk_i); | |
| while (!src_done || dst_mbox.num() > 0) begin | |
| static integer expected, actual; | |
| static int cooldown; | |
| dst_ready_i <= #(tck_dst*0.2) 1; | |
| dst_cycle_start(); | |
| while (!dst_valid_o) begin | |
| dst_cycle_end(); | |
| dst_cycle_start(); | |
| end | |
| actual = dst_data_o; | |
| num_received++; | |
| if (dst_mbox.num() == 0) begin | |
| $error("unexpected transaction: data=%0h", actual); | |
| num_failed++; | |
| end else begin | |
| dst_mbox.get(expected); | |
| if (actual != expected) begin | |
| $error("transaction mismatch: exp=%0h, act=%0h", expected, actual); | |
| num_failed++; | |
| end | |
| end | |
| dst_cycle_end(); | |
| dst_ready_i <= #(tck_dst*0.2) 0; | |
| cooldown = $urandom_range(0, 40); | |
| if (cooldown < 20) repeat(cooldown) @(posedge dst_clk_i); | |
| end | |
| if (num_sent != num_received) begin | |
| $error("%0d items sent, but %0d items received", num_sent, num_received); | |
| end | |
| if (num_failed > 0) begin | |
| $error("%0d/%0d items mismatched", num_failed, num_sent); | |
| end else begin | |
| $info("%0d items passed", num_sent); | |
| end | |
| dst_done = 1; | |
| end | |
| endmodule | |
| module cdc_2phase_tb_delay_injector #( | |
| parameter time MAX_DELAY = 0ns | |
| )( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input logic [31:0] src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| output logic [31:0] dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| logic async_req_o, async_req_i; | |
| logic async_ack_o, async_ack_i; | |
| logic [31:0] async_data_o, async_data_i; | |
| always @(async_req_o) begin | |
| automatic time d = $urandom_range(0, MAX_DELAY); | |
| async_req_i <= #d async_req_o; | |
| end | |
| always @(async_ack_o) begin | |
| automatic time d = $urandom_range(0, MAX_DELAY); | |
| async_ack_i <= #d async_ack_o; | |
| end | |
| for (genvar i = 0; i < 32; i++) begin | |
| always @(async_data_o[i]) begin | |
| automatic time d = $urandom_range(0, MAX_DELAY); | |
| async_data_i[i] <= #d async_data_o[i]; | |
| end | |
| end | |
| cdc_2phase_src #(logic [31:0]) i_src ( | |
| .rst_ni ( src_rst_ni ), | |
| .clk_i ( src_clk_i ), | |
| .data_i ( src_data_i ), | |
| .valid_i ( src_valid_i ), | |
| .ready_o ( src_ready_o ), | |
| .async_req_o ( async_req_o ), | |
| .async_ack_i ( async_ack_i ), | |
| .async_data_o ( async_data_o ) | |
| ); | |
| cdc_2phase_dst #(logic [31:0]) i_dst ( | |
| .rst_ni ( dst_rst_ni ), | |
| .clk_i ( dst_clk_i ), | |
| .data_o ( dst_data_o ), | |
| .valid_o ( dst_valid_o ), | |
| .ready_i ( dst_ready_i ), | |
| .async_req_i ( async_req_i ), | |
| .async_ack_o ( async_ack_o ), | |
| .async_data_i ( async_data_i ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cdc_2phase_clearable_tb; | |
| parameter int UNTIL = 100000; | |
| parameter bit INJECT_DELAYS = 1; | |
| parameter int CLEAR_PPM = 2000; | |
| parameter int SYNC_STAGES = 3; | |
| time tck_src = 10ns; | |
| time tck_dst = 10ns; | |
| bit src_done = 0; | |
| bit dst_done = 0; | |
| bit done; | |
| assign done = src_done & dst_done; | |
| logic src_rst_ni = 1; | |
| logic src_clk_i = 0; | |
| logic [31:0] src_data_i = 0; | |
| logic src_clear_i = 0; | |
| logic src_clear_pending_o; | |
| logic src_valid_i = 0; | |
| logic src_ready_o; | |
| logic dst_rst_ni = 1; | |
| logic dst_clk_i = 0; | |
| logic dst_clear_i = 0; | |
| logic dst_clear_pending_o; | |
| logic [31:0] dst_data_o; | |
| logic dst_valid_o; | |
| logic dst_ready_i = 0; | |
| if (INJECT_DELAYS) begin : g_dut | |
| cdc_2phase_clearable_tb_delay_injector #(0.8ns) i_dut (.*); | |
| end else begin : g_dut | |
| cdc_2phase_clearable #(logic [31:0]) i_dut (.*); | |
| end | |
| typedef struct { | |
| int data; | |
| bit is_stale; | |
| } item_t; | |
| item_t dst_mbox[$]; | |
| int num_sent = 0; | |
| int num_received = 0; | |
| int num_failed = 0; | |
| initial begin | |
| static int num_items, num_clks; | |
| num_items = 10; | |
| num_clks = 0; | |
| #10ns; | |
| src_rst_ni = 0; | |
| #10ns; | |
| src_rst_ni = 1; | |
| #10ns; | |
| while (!done) begin | |
| src_clk_i = 1; | |
| #(tck_src/2); | |
| src_clk_i = 0; | |
| #(tck_src/2); | |
| num_clks++; | |
| if (num_sent >= num_items && num_clks > 10) begin | |
| num_items = num_sent + 10; | |
| num_clks = 0; | |
| tck_src = $urandom_range(1000, 10000) * 1ps; | |
| assert(tck_src > 0); | |
| end | |
| end | |
| end | |
| initial begin | |
| static int num_items, num_clks; | |
| num_items = 10; | |
| num_clks = 0; | |
| #10ns; | |
| dst_rst_ni = 0; | |
| #10ns; | |
| dst_rst_ni = 1; | |
| #10ns; | |
| while (!done) begin | |
| dst_clk_i = 1; | |
| #(tck_dst/2); | |
| dst_clk_i = 0; | |
| #(tck_dst/2); | |
| num_clks++; | |
| if (num_received >= num_items && num_clks > 10) begin | |
| num_items = num_received + 10; | |
| num_clks = 0; | |
| tck_dst = $urandom_range(1000, 10000) * 1ps; | |
| assert(tck_dst > 0); | |
| end | |
| end | |
| end | |
| task src_cycle_start; | |
| #(tck_src*0.8); | |
| endtask | |
| task src_cycle_end; | |
| @(posedge src_clk_i); | |
| endtask | |
| initial begin | |
| @(negedge src_rst_ni); | |
| @(posedge src_rst_ni); | |
| repeat(3) @(posedge src_clk_i); | |
| for (int i = 0; i < UNTIL; i++) begin | |
| static item_t stimulus; | |
| static bit clear_cdc; | |
| stimulus.data = $random(); | |
| stimulus.is_stale = 1'b0; | |
| src_data_i <= #(tck_src*0.2) stimulus.data; | |
| src_valid_i <= #(tck_src*0.2) 1; | |
| dst_mbox.push_front(stimulus); | |
| num_sent++; | |
| src_cycle_start(); | |
| while (!src_ready_o) begin | |
| src_cycle_end(); | |
| src_cycle_start(); | |
| clear_cdc = $urandom_range(0,1e6) < CLEAR_PPM; | |
| if (clear_cdc && !src_clear_pending_o) begin | |
| foreach(dst_mbox[i]) begin | |
| if (!dst_mbox[i].is_stale) begin | |
| dst_mbox[i].is_stale = 1'b1; | |
| num_sent--; | |
| end | |
| end | |
| if ($urandom_range(0,1) == 1) begin | |
| $info("Randomly clearing CDC source-side synchronously"); | |
| src_cycle_start(); | |
| src_clear_i = 1'b1; | |
| src_valid_i = 1'b0; | |
| src_cycle_end(); | |
| src_clear_i = #(tck_src*0.2) 1'b0; | |
| end else begin | |
| $info("Randomly resetting CDC source-side asynchronously"); | |
| src_cycle_start(); | |
| src_rst_ni = 1'b0; | |
| src_valid_i = 1'b0; | |
| src_cycle_end(); | |
| src_rst_ni = #(tck_src*0.2) 1'b1; | |
| end | |
| break; | |
| end | |
| end | |
| src_cycle_end(); | |
| src_valid_i <= #(tck_src*0.2) 0; | |
| end | |
| src_done = 1; | |
| end | |
| task dst_cycle_start; | |
| #(tck_dst*0.8); | |
| endtask | |
| task dst_cycle_end; | |
| @(posedge dst_clk_i); | |
| endtask | |
| initial begin | |
| @(negedge dst_rst_ni); | |
| @(posedge dst_rst_ni); | |
| repeat(3) @(posedge dst_clk_i); | |
| while (!src_done || dst_mbox.size() > 0) begin | |
| static item_t expected; | |
| static integer actual; | |
| static int cooldown; | |
| static bit clear_cdc; | |
| clear_cdc = $urandom_range(0,1e6) < CLEAR_PPM; | |
| if (clear_cdc && !dst_clear_pending_o) begin | |
| if ($urandom_range(0,1) == 1) begin | |
| $info("Randomly clearing CDC destination-side synchronously"); | |
| dst_cycle_start(); | |
| dst_clear_i = 1'b1; | |
| dst_ready_i = 1'b0; | |
| dst_cycle_end(); | |
| dst_clear_i = #(tck_dst*0.2) 1'b0; | |
| end else begin | |
| $info("Randomly resetting CDC destination-side asynchronously"); | |
| dst_cycle_start(); | |
| dst_rst_ni = 1'b0; | |
| dst_ready_i = 1'b0; | |
| dst_cycle_end(); | |
| dst_rst_ni = #(tck_dst*0.2) 1'b1; | |
| end | |
| @(posedge dst_clk_i); | |
| repeat(SYNC_STAGES) @(posedge src_clk_i); | |
| dst_cycle_end(); | |
| while (dst_mbox.size() > 1) begin | |
| expected = dst_mbox.pop_back(); | |
| end | |
| end else begin | |
| dst_ready_i <= #(tck_dst*0.2) 1; | |
| dst_cycle_start(); | |
| while (!dst_valid_o) begin | |
| dst_cycle_end(); | |
| dst_cycle_start(); | |
| end | |
| actual = dst_data_o; | |
| num_received++; | |
| if (dst_mbox.size() == 0) begin | |
| $error("unexpected transaction: data=%0h", actual); | |
| num_failed++; | |
| end else begin | |
| expected = dst_mbox.pop_back(); | |
| if (actual != expected.data) begin | |
| while (dst_mbox.size() > 0 && expected.is_stale && expected.data != actual) begin | |
| expected = dst_mbox.pop_back(); | |
| end | |
| if (actual != expected.data) begin | |
| $error("transaction mismatch: exp=%0h, act=%0h", expected.data, actual); | |
| num_failed++; | |
| end else begin | |
| if (!expected.is_stale) begin | |
| num_received++; | |
| end | |
| end | |
| end else if (expected.is_stale) begin | |
| $info("Received stale item after clear. This is expected to happen for some cycles after the clear until the clear propagated to the other side."); | |
| end else begin | |
| num_received++; | |
| end | |
| end | |
| dst_cycle_end(); | |
| dst_ready_i <= #(tck_dst*0.2) 0; | |
| cooldown = $urandom_range(0, 40); | |
| if (cooldown < 20) repeat(cooldown) @(posedge dst_clk_i); | |
| end | |
| end | |
| if (num_failed > 0) begin | |
| $error("%0d/%0d items mismatched", num_failed, num_sent); | |
| end else begin | |
| $info("%0d items passed", num_sent); | |
| end | |
| dst_done = 1; | |
| end | |
| endmodule | |
| module cdc_2phase_clearable_tb_delay_injector #( | |
| parameter time MAX_DELAY = 0ns, | |
| parameter int SYNC_STAGES = 3 | |
| )( | |
| input logic src_rst_ni, | |
| input logic src_clk_i, | |
| input logic src_clear_i, | |
| output logic src_clear_pending_o, | |
| input logic [31:0] src_data_i, | |
| input logic src_valid_i, | |
| output logic src_ready_o, | |
| input logic dst_rst_ni, | |
| input logic dst_clk_i, | |
| input logic dst_clear_i, | |
| output logic dst_clear_pending_o, | |
| output logic [31:0] dst_data_o, | |
| output logic dst_valid_o, | |
| input logic dst_ready_i | |
| ); | |
| logic async_req_o, async_req_i; | |
| logic async_ack_o, async_ack_i; | |
| logic [31:0] async_data_o, async_data_i; | |
| logic s_src_clear; | |
| logic s_src_ready; | |
| logic s_dst_clear; | |
| logic s_dst_valid; | |
| always @(async_req_o) begin | |
| automatic time d = $urandom_range(1ps, MAX_DELAY); | |
| async_req_i <= #d async_req_o; | |
| end | |
| always @(async_ack_o) begin | |
| automatic time d = $urandom_range(1ps, MAX_DELAY); | |
| async_ack_i <= #d async_ack_o; | |
| end | |
| for (genvar i = 0; i < 32; i++) begin | |
| always @(async_data_o[i]) begin | |
| automatic time d = $urandom_range(1ps, MAX_DELAY); | |
| async_data_i[i] <= #d async_data_o[i]; | |
| end | |
| end | |
| cdc_2phase_src_clearable #(logic [31:0], SYNC_STAGES) i_src ( | |
| .rst_ni ( src_rst_ni ), | |
| .clk_i ( src_clk_i ), | |
| .clear_i ( s_src_clear ), | |
| .data_i ( src_data_i ), | |
| .valid_i ( src_valid_i & !s_src_clear ), | |
| .ready_o ( s_src_ready ), | |
| .async_req_o ( async_req_o ), | |
| .async_ack_i ( async_ack_i ), | |
| .async_data_o ( async_data_o ) | |
| ); | |
| assign src_ready_o = s_src_ready & !s_src_clear; | |
| cdc_2phase_dst_clearable #(logic [31:0], SYNC_STAGES) i_dst ( | |
| .rst_ni ( dst_rst_ni ), | |
| .clk_i ( dst_clk_i ), | |
| .clear_i ( s_dst_clear ), | |
| .data_o ( dst_data_o ), | |
| .valid_o ( s_dst_valid ), | |
| .ready_i ( dst_ready_i & !s_dst_clear ), | |
| .async_req_i ( async_req_i ), | |
| .async_ack_o ( async_ack_o ), | |
| .async_data_i ( async_data_i ) | |
| ); | |
| assign dst_valid_o = s_dst_valid & !s_dst_clear; | |
| cdc_reset_ctrlr #( | |
| .SYNC_STAGES(SYNC_STAGES-1) | |
| ) i_cdc_reset_ctrlr ( | |
| .a_clk_i ( src_clk_i ), | |
| .a_rst_ni ( src_rst_ni ), | |
| .a_clear_i ( src_clear_i ), | |
| .a_clear_o ( s_src_clear ), | |
| .a_clear_ack_i ( '0 ), | |
| .a_isolate_o ( ), | |
| .a_isolate_ack_i( '0 ), | |
| .b_clk_i ( dst_clk_i ), | |
| .b_rst_ni ( dst_rst_ni ), | |
| .b_clear_i ( dst_clear_i ), | |
| .b_clear_o ( s_dst_clear ), | |
| .b_clear_ack_i ( '0 ), | |
| .b_isolate_o ( ), | |
| .b_isolate_ack_i( '0 ) | |
| ); | |
| assign src_clear_pending_o = s_src_clear; | |
| assign dst_clear_pending_o = s_dst_clear; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cdc_fifo_tb; | |
| parameter bit INJECT_SRC_STALLS = 0; | |
| parameter bit INJECT_DST_STALLS = 0; | |
| parameter int UNTIL = 100000; | |
| parameter int DEPTH = 0; | |
| parameter bit GRAY = 0; | |
| time tck_src = 10ns; | |
| time tck_dst = 10ns; | |
| bit src_done = 0; | |
| bit dst_done = 0; | |
| bit done; | |
| assign done = src_done & dst_done; | |
| logic src_rst_ni = 1; | |
| logic src_clk_i = 0; | |
| logic [31:0] src_data_i = 0; | |
| logic src_valid_i = 0; | |
| logic src_ready_o; | |
| logic dst_rst_ni = 1; | |
| logic dst_clk_i = 0; | |
| logic [31:0] dst_data_o; | |
| logic dst_valid_o; | |
| logic dst_ready_i = 0; | |
| assert property (@(posedge src_clk_i) !$isunknown(src_valid_i) && !$isunknown(src_ready_o)); | |
| assert property (@(posedge dst_clk_i) !$isunknown(dst_valid_o) && !$isunknown(dst_ready_i)); | |
| assert property (@(posedge src_clk_i) src_valid_i |-> !$isunknown(src_data_i)); | |
| assert property (@(posedge dst_clk_i) dst_valid_o |-> !$isunknown(dst_data_o)); | |
| if (GRAY) | |
| cdc_fifo_gray #(.T(logic [31:0]), .LOG_DEPTH(DEPTH)) i_dut (.*); | |
| else | |
| cdc_fifo_2phase #(.T(logic [31:0]), .LOG_DEPTH(DEPTH)) i_dut (.*); | |
| mailbox #(int) dst_mbox = new(); | |
| int num_sent = 0; | |
| int num_received = 0; | |
| int num_failed = 0; | |
| initial begin | |
| static int num_items, num_clks; | |
| num_items = 10; | |
| num_clks = 0; | |
| #10ns; | |
| src_rst_ni = 0; | |
| #10ns; | |
| src_rst_ni = 1; | |
| #10ns; | |
| while (!done) begin | |
| src_clk_i = 1; | |
| #(tck_src/2); | |
| src_clk_i = 0; | |
| #(tck_src/2); | |
| num_clks++; | |
| if (num_sent >= num_items && num_clks > 10) begin | |
| num_items = num_sent + 10; | |
| num_clks = 0; | |
| tck_src = $urandom_range(1000, 10000) * 1ps; | |
| assert(tck_src > 0); | |
| end | |
| end | |
| end | |
| initial begin | |
| static int num_items, num_clks; | |
| num_items = 10; | |
| num_clks = 0; | |
| #10ns; | |
| dst_rst_ni = 0; | |
| #10ns; | |
| dst_rst_ni = 1; | |
| #10ns; | |
| while (!done) begin | |
| dst_clk_i = 1; | |
| #(tck_dst/2); | |
| dst_clk_i = 0; | |
| #(tck_dst/2); | |
| num_clks++; | |
| if (num_received >= num_items && num_clks > 10) begin | |
| num_items = num_received + 10; | |
| num_clks = 0; | |
| tck_dst = $urandom_range(1000, 10000) * 1ps; | |
| assert(tck_dst > 0); | |
| end | |
| end | |
| end | |
| task src_cycle_start; | |
| #(tck_src*0.8); | |
| endtask | |
| task src_cycle_end; | |
| @(posedge src_clk_i); | |
| endtask | |
| initial begin | |
| @(negedge src_rst_ni); | |
| @(posedge src_rst_ni); | |
| repeat(3) @(posedge src_clk_i); | |
| for (int i = 0; i < UNTIL; i++) begin | |
| static integer stimulus; | |
| static int cooldown; | |
| stimulus = $random(); | |
| src_data_i <= #(tck_src*0.2) stimulus; | |
| src_valid_i <= #(tck_src*0.2) 1; | |
| dst_mbox.put(stimulus); | |
| num_sent++; | |
| src_cycle_start(); | |
| while (!src_ready_o) begin | |
| src_cycle_end(); | |
| src_cycle_start(); | |
| end | |
| src_cycle_end(); | |
| src_valid_i <= #(tck_src*0.2) 0; | |
| if (INJECT_SRC_STALLS) begin | |
| cooldown = $urandom_range(0, 40); | |
| if (cooldown < 20) repeat(cooldown) @(posedge dst_clk_i); | |
| end | |
| end | |
| src_done = 1; | |
| end | |
| task dst_cycle_start; | |
| #(tck_dst*0.8); | |
| endtask | |
| task dst_cycle_end; | |
| @(posedge dst_clk_i); | |
| endtask | |
| initial begin | |
| @(negedge dst_rst_ni); | |
| @(posedge dst_rst_ni); | |
| repeat(3) @(posedge dst_clk_i); | |
| while (!src_done || dst_mbox.num() > 0) begin | |
| static integer expected, actual; | |
| static int cooldown; | |
| dst_ready_i <= #(tck_dst*0.2) 1; | |
| dst_cycle_start(); | |
| while (!dst_valid_o) begin | |
| dst_cycle_end(); | |
| dst_cycle_start(); | |
| end | |
| actual = dst_data_o; | |
| num_received++; | |
| if (dst_mbox.num() == 0) begin | |
| $error("unexpected transaction: data=%0h", actual); | |
| num_failed++; | |
| end else begin | |
| dst_mbox.get(expected); | |
| if (actual != expected) begin | |
| $error("transaction mismatch: exp=%0h, act=%0h", expected, actual); | |
| num_failed++; | |
| end | |
| end | |
| dst_cycle_end(); | |
| dst_ready_i <= #(tck_dst*0.2) 0; | |
| if (INJECT_DST_STALLS) begin | |
| cooldown = $urandom_range(0, 40); | |
| if (cooldown < 20) repeat(cooldown) @(posedge dst_clk_i); | |
| end | |
| end | |
| if (num_sent != num_received) begin | |
| $error("%0d items sent, but %0d items received", num_sent, num_received); | |
| end | |
| if (num_failed > 0) begin | |
| $error("%0d/%0d items mismatched", num_failed, num_sent); | |
| end else begin | |
| $info("%0d items passed", num_sent); | |
| end | |
| dst_done = 1; | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module cdc_fifo_clearable_tb; | |
| parameter bit INJECT_SRC_STALLS = 0; | |
| parameter bit INJECT_DST_STALLS = 0; | |
| parameter int UNTIL = 100000; | |
| parameter int DEPTH = 3; | |
| parameter int CLEAR_PPM = 2000; | |
| time tck_src = 10ns; | |
| time tck_dst = 27ns; | |
| bit src_done = 0; | |
| bit dst_done = 0; | |
| bit done; | |
| assign done = src_done & dst_done; | |
| logic src_rst_ni = 1; | |
| logic src_clk_i = 0; | |
| logic src_clear_i = 0; | |
| logic src_clear_pending_o; | |
| logic [31:0] src_data_i = 0; | |
| logic src_valid_i = 0; | |
| logic src_ready_o; | |
| logic dst_rst_ni = 1; | |
| logic dst_clk_i = 0; | |
| logic dst_clear_i = 0; | |
| logic dst_clear_pending_o; | |
| logic [31:0] dst_data_o; | |
| logic dst_valid_o; | |
| logic dst_ready_i = 0; | |
| assert property (@(posedge src_clk_i) !$isunknown(src_valid_i) && !$isunknown(src_ready_o)); | |
| assert property (@(posedge dst_clk_i) !$isunknown(dst_valid_o) && !$isunknown(dst_ready_i)); | |
| assert property (@(posedge src_clk_i) src_valid_i |-> !$isunknown(src_data_i)); | |
| assert property (@(posedge dst_clk_i) dst_valid_o |-> !$isunknown(dst_data_o)); | |
| cdc_fifo_gray_clearable #(.T(logic [31:0]), .LOG_DEPTH(DEPTH)) i_dut (.*); | |
| typedef struct { | |
| int data; | |
| bit is_stale; | |
| } item_t; | |
| item_t dst_mbox[$]; | |
| int num_sent = 0; | |
| int num_received = 0; | |
| int num_failed = 0; | |
| initial begin | |
| static int num_items, num_clks; | |
| num_items = 10; | |
| num_clks = 0; | |
| #10ns; | |
| src_rst_ni = 0; | |
| #10ns; | |
| src_rst_ni = 1; | |
| #10ns; | |
| while (!done) begin | |
| src_clk_i = 1; | |
| #(tck_src/2); | |
| src_clk_i = 0; | |
| #(tck_src/2); | |
| num_clks++; | |
| if (num_sent >= num_items && num_clks > 10) begin | |
| num_items = num_sent + 10; | |
| num_clks = 0; | |
| tck_src = $urandom_range(1000, 10000) * 1ps; | |
| assert(tck_src > 0); | |
| end | |
| end | |
| end | |
| initial begin | |
| static int num_items, num_clks; | |
| num_items = 10; | |
| num_clks = 0; | |
| #10ns; | |
| dst_rst_ni = 0; | |
| #10ns; | |
| dst_rst_ni = 1; | |
| #10ns; | |
| while (!done) begin | |
| dst_clk_i = 1; | |
| #(tck_dst/2); | |
| dst_clk_i = 0; | |
| #(tck_dst/2); | |
| num_clks++; | |
| if (num_received >= num_items && num_clks > 10) begin | |
| num_items = num_received + 10; | |
| num_clks = 0; | |
| tck_dst = $urandom_range(1000, 10000) * 1ps; | |
| assert(tck_dst > 0); | |
| end | |
| end | |
| end | |
| task src_cycle_start; | |
| #(tck_src*0.8); | |
| endtask | |
| task src_cycle_end; | |
| @(posedge src_clk_i); | |
| endtask | |
| initial begin | |
| @(negedge src_rst_ni); | |
| @(posedge src_rst_ni); | |
| repeat(3) @(posedge src_clk_i); | |
| for (int i = 0; i < UNTIL; i++) begin | |
| item_t item; | |
| static integer stimulus; | |
| static int cooldown; | |
| static bit clear_cdc; | |
| clear_cdc = $urandom_range(0,1e6) < CLEAR_PPM; | |
| if (!clear_cdc || src_clear_pending_o) begin | |
| stimulus = $random(); | |
| item.data = stimulus; | |
| item.is_stale = 1'b0; | |
| src_data_i <= #(tck_src*0.2) stimulus; | |
| src_valid_i <= #(tck_src*0.2) 1; | |
| num_sent++; | |
| src_cycle_start(); | |
| while (!src_ready_o) begin | |
| src_cycle_end(); | |
| src_cycle_start(); | |
| end | |
| dst_mbox.push_front(item); | |
| src_cycle_end(); | |
| src_valid_i <= #(tck_src*0.2) 0; | |
| if (INJECT_SRC_STALLS) begin | |
| cooldown = $urandom_range(0, 40); | |
| if (cooldown < 20) repeat(cooldown) @(posedge src_clk_i); | |
| end | |
| end else begin | |
| foreach(dst_mbox[i]) begin | |
| if (!dst_mbox[i].is_stale) begin | |
| dst_mbox[i].is_stale = 1'b1; | |
| num_sent--; | |
| end | |
| end | |
| if ($urandom_range(0,1) == 1) begin | |
| $info("Randomly clearing CDC synchronously and marking all pending items as stale"); | |
| src_cycle_start(); | |
| src_clear_i = 1'b1; | |
| src_cycle_end(); | |
| src_clear_i = #(tck_src*0.2) 1'b0; | |
| end else begin | |
| $info("Randomly resetting CDC asynchronously and marking all pending items as stale"); | |
| src_cycle_start(); | |
| src_rst_ni = 1'b0; | |
| src_cycle_end(); | |
| src_rst_ni = #(tck_src*0.2) 1'b1; | |
| end | |
| end | |
| end | |
| src_done = 1; | |
| end | |
| task dst_cycle_start; | |
| #(tck_dst*0.8); | |
| endtask | |
| task dst_cycle_end; | |
| @(posedge dst_clk_i); | |
| endtask | |
| initial begin | |
| @(negedge dst_rst_ni); | |
| @(posedge dst_rst_ni); | |
| repeat(3) @(posedge dst_clk_i); | |
| while (!src_done || dst_mbox.size() > 0) begin | |
| static item_t expected_item; | |
| static integer actual; | |
| static int cooldown; | |
| static bit clear_cdc; | |
| clear_cdc = $urandom_range(0,1e6) < CLEAR_PPM; | |
| if (!clear_cdc || dst_clear_pending_o) begin | |
| dst_ready_i <= #(tck_dst*0.2) 1; | |
| dst_cycle_start(); | |
| while (!dst_valid_o && !src_done) begin | |
| dst_cycle_end(); | |
| dst_cycle_start(); | |
| end | |
| if (src_done) break; | |
| actual = dst_data_o; | |
| if (dst_mbox.size() == 0) begin | |
| $error("unexpected transaction: data=%0h", actual); | |
| num_failed++; | |
| end else begin | |
| expected_item = dst_mbox.pop_back(); | |
| if (actual != expected_item.data) begin | |
| while (dst_mbox.size() > 0 && expected_item.is_stale && expected_item.data != actual) begin | |
| expected_item = dst_mbox.pop_back(); | |
| end | |
| if (actual != expected_item.data) begin | |
| $error("transaction mismatch: exp=%0h, act=%0h", expected_item.data, actual); | |
| num_failed++; | |
| end else begin | |
| if (!expected_item.is_stale) begin | |
| num_received++; | |
| end | |
| end | |
| end else if (expected_item.is_stale) begin | |
| $info("Received stale item after clear. This is expected to happen for some cycles after the clear until the clear propagated to the other side."); | |
| end else begin | |
| num_received++; | |
| end | |
| end | |
| dst_cycle_end(); | |
| dst_ready_i <= #(tck_dst*0.2) 0; | |
| if (INJECT_DST_STALLS) begin | |
| cooldown = $urandom_range(0, 40); | |
| if (cooldown < 20) repeat(cooldown) @(posedge dst_clk_i); | |
| end | |
| end else begin | |
| if ($urandom_range(0,1) == 1) begin | |
| $info("Randomly clearing CDC synchronously from the destination side"); | |
| dst_cycle_start(); | |
| dst_clear_i = 1'b1; | |
| dst_cycle_end(); | |
| dst_clear_i <= #(tck_dst*0.2) 1'b0; | |
| end else begin | |
| $info("Randomly resettting CDC asynchronously from the destination side"); | |
| dst_cycle_start(); | |
| dst_rst_ni = 1'b0; | |
| dst_cycle_end(); | |
| dst_rst_ni <= #(tck_dst*0.2) 1'b1; | |
| end | |
| @(posedge dst_clk_i); | |
| repeat(DEPTH) @(posedge src_clk_i); | |
| num_sent-=dst_mbox.size(); | |
| dst_mbox.delete(); | |
| dst_cycle_end(); | |
| end | |
| end | |
| if (num_failed > 0) begin | |
| $error("%0d/%0d items mismatched", num_failed, num_sent); | |
| end else begin | |
| $info("%0d items passed", num_sent); | |
| end | |
| dst_done = 1; | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module fifo_inst_tb #( | |
| parameter bit FALL_THROUGH, | |
| parameter int unsigned DEPTH, | |
| parameter int unsigned DATA_WIDTH = 8, | |
| parameter int unsigned N_CHECKS, | |
| parameter time TA, | |
| parameter time TT | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| output logic done_o | |
| ); | |
| import rand_verif_pkg::rand_wait; | |
| typedef logic [DATA_WIDTH-1:0] data_t; | |
| logic clk, | |
| flush, | |
| full, | |
| empty, | |
| push, | |
| pop, | |
| try_push, | |
| try_pop; | |
| data_t wdata, | |
| rdata; | |
| int unsigned n_checks = 0; | |
| assign clk = clk_i; | |
| fifo_v3 #( | |
| .FALL_THROUGH ( FALL_THROUGH ), | |
| .DATA_WIDTH ( DATA_WIDTH ), | |
| .DEPTH ( DEPTH ) | |
| ) dut ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( flush ), | |
| .testmode_i ( 1'b0 ), | |
| .full_o ( full ), | |
| .empty_o ( empty ), | |
| .usage_o ( ), | |
| .data_i ( wdata ), | |
| .push_i ( push ), | |
| .data_o ( rdata ), | |
| .pop_i ( pop ) | |
| ); | |
| initial begin | |
| done_o = 1'b0; | |
| $display("%m: Running test with FALL_THROUGH=%0d, DEPTH=%0d", FALL_THROUGH, DEPTH); | |
| wait (n_checks >= N_CHECKS); | |
| done_o = 1'b1; | |
| $display("%m: Checked %0d stimuli", n_checks); | |
| end | |
| class random_action_t; | |
| rand logic [1:0] action; | |
| constraint random_action { | |
| action dist { | |
| 0 := 40, | |
| 1 := 40, | |
| 3 := 2, | |
| 0 := 0 | |
| }; | |
| } | |
| endclass | |
| assign push = try_push & ~full; | |
| initial begin | |
| automatic random_action_t rand_act = new(); | |
| flush <= 1'b0; | |
| wdata <= 'x; | |
| try_push <= 1'b0; | |
| wait (rst_ni); | |
| forever begin | |
| static logic rand_success; | |
| rand_wait(1, 8, clk); | |
| rand_success = rand_act.randomize(); assert(rand_success); | |
| case (rand_act.action) | |
| 0: begin | |
| wdata <= #TA $random(); | |
| try_push <= #TA 1'b1; | |
| end | |
| 1: begin | |
| wdata <= #TA $random(); | |
| try_push <= #TA 1'b0; | |
| end | |
| 2: begin | |
| flush <= #TA 1'b1; | |
| rand_wait(1, 8, clk); | |
| flush <= #TA 1'b0; | |
| end | |
| endcase | |
| end | |
| end | |
| assign pop = try_pop & ~empty; | |
| initial begin | |
| try_pop <= 1'b0; | |
| wait (rst_ni); | |
| forever begin | |
| rand_wait(1, 8, clk); | |
| try_pop <= #TA $random(); | |
| end | |
| end | |
| initial begin | |
| data_t queue[$]; | |
| wait (rst_ni); | |
| forever begin | |
| @(posedge clk_i); | |
| #(TT); | |
| if (flush) begin | |
| queue = {}; | |
| end else begin | |
| if (push && !full) begin | |
| queue.push_back(wdata); | |
| end | |
| if (pop && !empty) begin | |
| automatic data_t data = queue.pop_front(); | |
| assert (rdata == data) else $error("Queue output %0x != %0x", rdata, data); | |
| n_checks++; | |
| end | |
| end | |
| end | |
| end | |
| endmodule | |
| module fifo_tb #( | |
| parameter int unsigned N_CHECKS = 100000, | |
| parameter time TCLK = 10ns, | |
| parameter time TA = TCLK * 1/4, | |
| parameter time TT = TCLK * 3/4 | |
| ); | |
| logic clk, | |
| rst_n; | |
| logic [5:0] done; | |
| clk_rst_gen #(.ClkPeriod(TCLK), .RstClkCycles(10)) i_clk_rst_gen ( | |
| .clk_o (clk), | |
| .rst_no (rst_n) | |
| ); | |
| fifo_inst_tb #( | |
| .FALL_THROUGH (1'b0), | |
| .DEPTH (8), | |
| .N_CHECKS (N_CHECKS), | |
| .TA (TA), | |
| .TT (TT) | |
| ) i_tb_8 ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .done_o (done[0]) | |
| ); | |
| fifo_inst_tb #( | |
| .FALL_THROUGH (1'b1), | |
| .DEPTH (8), | |
| .N_CHECKS (N_CHECKS), | |
| .TA (TA), | |
| .TT (TT) | |
| ) i_tb_ft_8 ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .done_o (done[1]) | |
| ); | |
| fifo_inst_tb #( | |
| .FALL_THROUGH (1'b0), | |
| .DEPTH (1), | |
| .N_CHECKS (N_CHECKS), | |
| .TA (TA), | |
| .TT (TT) | |
| ) i_tb_1 ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .done_o (done[2]) | |
| ); | |
| fifo_inst_tb #( | |
| .FALL_THROUGH (1'b1), | |
| .DEPTH (1), | |
| .N_CHECKS (N_CHECKS), | |
| .TA (TA), | |
| .TT (TT) | |
| ) i_tb_ft_1 ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .done_o (done[3]) | |
| ); | |
| fifo_inst_tb #( | |
| .FALL_THROUGH (1'b0), | |
| .DEPTH (9), | |
| .N_CHECKS (N_CHECKS), | |
| .TA (TA), | |
| .TT (TT) | |
| ) i_tb_9 ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .done_o (done[4]) | |
| ); | |
| fifo_inst_tb #( | |
| .FALL_THROUGH (1'b1), | |
| .DEPTH (9), | |
| .N_CHECKS (N_CHECKS), | |
| .TA (TA), | |
| .TT (TT) | |
| ) i_tb_ft_9 ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .done_o (done[5]) | |
| ); | |
| initial begin | |
| wait ((&done)); | |
| $finish(); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module graycode_tb #( | |
| parameter int N = 9 | |
| ); | |
| logic [N-1:0] a, b, c, bp = '0; | |
| binary_to_gray #(N) dut_ab (a,b); | |
| gray_to_binary #(N) dut_bc (b,c); | |
| task check; | |
| assert(a == c); | |
| assert($signed($countones(b) - $countones(bp)) inside {-1,0,1}); | |
| bp = b; | |
| endtask | |
| initial begin : p_stim | |
| logic [N:0] i; | |
| repeat(2) for (i = 0; i < 2**N; i++) begin | |
| a = i; | |
| #1; | |
| check(); | |
| end | |
| for (i = 0; i < 2**N; i++) begin | |
| a = N-i-1; | |
| #1; | |
| check(); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module id_queue_tb #( | |
| parameter int ID_WIDTH = 10, | |
| parameter int CAPACITY = 30, | |
| parameter int unsigned INP_MIN_WAIT_CYCLES = 0, | |
| parameter int unsigned INP_MAX_WAIT_CYCLES = 40, | |
| parameter int unsigned OUP_MIN_WAIT_CYCLES = 0, | |
| parameter int unsigned OUP_MAX_WAIT_CYCLES = INP_MAX_WAIT_CYCLES/2, | |
| parameter int unsigned N_CHECKS = 10000, | |
| parameter bit VERBOSE = 1'b0, | |
| parameter type data_t = logic[3:0] | |
| ); | |
| localparam time TCLK = 10ns; | |
| localparam time TA = TCLK * 1/4; | |
| localparam time TT = TCLK * 3/4; | |
| typedef logic [ID_WIDTH-1:0] id_t; | |
| typedef logic [$bits(data_t)-1:0] mask_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| } queue_t; | |
| typedef struct packed { | |
| data_t data; | |
| mask_t mask; | |
| } exists_t; | |
| logic clk, | |
| rst_n; | |
| data_t inp_data, | |
| oup_data; | |
| exists_t exists_inp; | |
| id_t inp_id, | |
| oup_id; | |
| queue_t queue_inp; | |
| logic exists, | |
| exists_req, exists_gnt, | |
| inp_req, inp_gnt, | |
| oup_req, oup_gnt, | |
| oup_pop, | |
| oup_data_valid; | |
| clk_rst_gen #( | |
| .ClkPeriod (TCLK), | |
| .RstClkCycles (5) | |
| ) i_clk_rst_gen ( | |
| .clk_o (clk), | |
| .rst_no (rst_n) | |
| ); | |
| id_queue #( | |
| .ID_WIDTH (ID_WIDTH), | |
| .CAPACITY (CAPACITY), | |
| .data_t (data_t) | |
| ) dut ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .inp_id_i (inp_id), | |
| .inp_data_i (inp_data), | |
| .inp_req_i (inp_req), | |
| .inp_gnt_o (inp_gnt), | |
| .exists_data_i (exists_inp.data), | |
| .exists_mask_i (exists_inp.mask), | |
| .exists_req_i (exists_req), | |
| .exists_o (exists), | |
| .exists_gnt_o (exists_gnt), | |
| .oup_id_i (oup_id), | |
| .oup_pop_i (oup_pop), | |
| .oup_req_i (oup_req), | |
| .oup_data_o (oup_data), | |
| .oup_data_valid_o (oup_data_valid), | |
| .oup_gnt_o (oup_gnt) | |
| ); | |
| rand_stream_mst #( | |
| .data_t (queue_t), | |
| .MinWaitCycles (INP_MIN_WAIT_CYCLES), | |
| .MaxWaitCycles (INP_MAX_WAIT_CYCLES), | |
| .ApplDelay (TA), | |
| .AcqDelay (TT) | |
| ) i_inp_mst ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .data_o (queue_inp), | |
| .valid_o (inp_req), | |
| .ready_i (inp_gnt) | |
| ); | |
| assign inp_id = queue_inp.id; | |
| assign inp_data = queue_inp.data; | |
| rand_stream_mst #( | |
| .data_t (logic), | |
| .MinWaitCycles (OUP_MIN_WAIT_CYCLES), | |
| .MaxWaitCycles (OUP_MAX_WAIT_CYCLES), | |
| .ApplDelay (TA), | |
| .AcqDelay (TT) | |
| ) i_oup_mst ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .data_o (), | |
| .valid_o (oup_req), | |
| .ready_i (oup_gnt) | |
| ); | |
| rand_stream_mst #( | |
| .data_t (exists_t), | |
| .MinWaitCycles (OUP_MIN_WAIT_CYCLES), | |
| .MaxWaitCycles (OUP_MAX_WAIT_CYCLES), | |
| .ApplDelay (TA), | |
| .AcqDelay (TT) | |
| ) i_exists_mst ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .data_o (exists_inp), | |
| .valid_o (exists_req), | |
| .ready_i (exists_gnt) | |
| ); | |
| import rand_id_queue_pkg::*; | |
| rand_id_queue #( | |
| .data_t (data_t), | |
| .ID_WIDTH (ID_WIDTH) | |
| ) exp_queue = new; | |
| initial begin | |
| wait (rst_n); | |
| forever begin | |
| @(posedge clk); | |
| if (inp_req && inp_gnt) begin | |
| exp_queue.push(inp_id, inp_data); | |
| if (VERBOSE) begin | |
| $display("%0t: new entry %0x at ID %0x", $time, inp_data, inp_id); | |
| end | |
| end | |
| if (oup_req && oup_gnt && oup_pop) begin | |
| if (VERBOSE) begin | |
| $display("%0t: removed entry from ID %0x", $time, oup_id); | |
| end | |
| void'(exp_queue.pop_id(oup_id)); | |
| end | |
| end | |
| end | |
| initial begin | |
| wait (rst_n); | |
| forever begin | |
| @(posedge clk); | |
| #(TT); | |
| if (exists_req && exists_gnt) begin | |
| automatic logic match = 1'b0; | |
| automatic mask_t mask = exists_inp.mask; | |
| automatic data_t masked_exists = exists_inp.data & mask; | |
| for (int unsigned id = 0; id < 2**ID_WIDTH; id++) begin | |
| for (int unsigned idx = 0; idx < exp_queue.queues[id].size(); idx++) begin | |
| match = ((exp_queue.queues[id][idx] & mask) == masked_exists); | |
| if (match) begin | |
| break; | |
| end | |
| end | |
| if (match) begin | |
| break; | |
| end | |
| end | |
| assert (exists == match) else begin | |
| if (match) begin | |
| $error("Entry with value %0x and mask %0b should exist but ID queue did not find it!", | |
| exists_inp.data, exists_inp.mask); | |
| end else begin | |
| $error("Entry with value %0x and mask %0b should NOT exist but ID queue found it!", | |
| exists_inp.data, exists_inp.mask); | |
| end | |
| end | |
| end | |
| if (oup_req && oup_gnt) begin | |
| if (oup_data_valid) begin | |
| automatic data_t exp_data = exp_queue.get(oup_id); | |
| assert (exp_data == oup_data) | |
| else $error("Expected to read %0x from ID %0x but got %0x!", | |
| exp_data, oup_id, oup_data); | |
| if (VERBOSE) begin | |
| $display("%0t: read %0x at ID %0x!", $time, oup_data, oup_id); | |
| end | |
| end else begin | |
| assert (exp_queue.queues[oup_id].size() == 0) | |
| else $error("Expected to get valid output from ID %0x but did not!", | |
| oup_id); | |
| end | |
| end | |
| end | |
| end | |
| initial begin | |
| void'(std::randomize(oup_id)); | |
| oup_pop = 1'b0; | |
| wait (rst_n); | |
| @(posedge clk); | |
| #(TT); | |
| forever begin | |
| @(posedge clk); | |
| #(TA); | |
| if (exp_queue.empty()) begin | |
| oup_pop = 1'b0; | |
| end else begin | |
| void'(std::randomize(oup_pop)); | |
| oup_id = exp_queue.rand_id(); | |
| end | |
| #(TT-TA); | |
| while (oup_req && !oup_gnt) begin | |
| @(posedge clk); | |
| #(TT); | |
| end | |
| end | |
| end | |
| initial begin | |
| static int unsigned n_pops = 0; | |
| wait (rst_n); | |
| forever begin | |
| @(posedge clk); | |
| #(TT); | |
| if (oup_req && oup_gnt && oup_pop && oup_data_valid) begin | |
| n_pops++; | |
| end | |
| #(TCLK-TT); | |
| if (n_pops >= N_CHECKS) begin | |
| $display("Finished with a total of %0d random entries fed through the ID queue.", | |
| n_pops); | |
| $finish(0); | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| `timescale 1ns/1ns | |
| module passthrough_stream_fifo_tb #( | |
| parameter int unsigned TCK = 10, | |
| parameter int unsigned DataWidth = 8, | |
| parameter int unsigned Depth = 10, | |
| parameter int unsigned NumStims = 1000, | |
| parameter int unsigned WriteProbability = 10, | |
| parameter int unsigned ReadProbability = 10, | |
| parameter bit SameCycleRW = 1'b1 | |
| ) (); | |
| typedef logic [DataWidth-1:0] data_t; | |
| int unsigned applied_stims, acquired_stims; | |
| logic clk, rst_n; | |
| data_t in_data, out_data; | |
| logic in_valid, in_ready, out_valid, out_ready; | |
| data_t app_queue[$], acq_queue[$]; | |
| clk_rst_gen #( | |
| .ClkPeriod ( TCK ), | |
| .RstClkCycles ( 1 ) | |
| ) i_clk_rst_gen ( | |
| .clk_o ( clk ), | |
| .rst_no ( rst_n ) | |
| ); | |
| passthrough_stream_fifo #( | |
| .Depth ( Depth ), | |
| .type_t ( data_t ), | |
| .PrintInfo ( 1'b1 ), | |
| .SameCycleRW ( SameCycleRW ) | |
| ) i_passthrough_stream_fifo ( | |
| .clk_i ( clk ), | |
| .rst_ni ( rst_n ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .data_i ( (in_valid && in_ready) ? in_data : 'x ), | |
| .valid_i ( in_valid && in_ready ), | |
| .ready_o ( in_ready ), | |
| .data_o ( out_data ), | |
| .valid_o ( out_valid ), | |
| .ready_i ( out_ready && out_valid ) | |
| ); | |
| initial begin | |
| applied_stims = 0; | |
| in_data = '0; | |
| in_valid = 1'b0; | |
| wait(rst_n); | |
| $display("Started application!"); | |
| while(applied_stims < NumStims) begin | |
| @(negedge clk); | |
| in_valid = $urandom_range(0, WriteProbability) == 0; | |
| in_data = $urandom(); | |
| @(posedge clk); | |
| if (in_valid && in_ready) begin | |
| $display("%d Applied: %d", applied_stims, in_data); | |
| app_queue.push_back(in_data); | |
| applied_stims++; | |
| end | |
| end | |
| in_valid = 1'b0; | |
| $display("Applied %d stimuli", applied_stims); | |
| end | |
| initial begin | |
| acquired_stims = 0; | |
| out_ready = 1'b0; | |
| wait(rst_n); | |
| $display("Started acquisition!"); | |
| forever begin | |
| @(negedge clk); | |
| out_ready = $urandom_range(0, ReadProbability) == 0; | |
| @(posedge clk); | |
| if (out_valid && out_ready) begin | |
| $display("%d Acquired: %d", acquired_stims, out_data); | |
| acq_queue.push_back(out_data); | |
| acquired_stims++; | |
| end | |
| end | |
| end | |
| initial begin | |
| int unsigned num_errors; | |
| data_t acq_data, app_data; | |
| num_errors = 0; | |
| while((acquired_stims < NumStims) || (applied_stims < NumStims)) begin | |
| wait((app_queue.size() != 0) && (acq_queue.size() != 0)); | |
| acq_data = acq_queue.pop_front(); | |
| app_data = app_queue.pop_front(); | |
| if (app_data != acq_data) begin | |
| $display("Missmatch! Applied: %d Acquired: %d", app_data, acq_data); | |
| num_errors++; | |
| end else begin | |
| $display("Match! Applied: %d Acquired: %d", app_data, acq_data); | |
| end | |
| end | |
| $display("Applied %d stimuli and acquired %d responses", applied_stims, acquired_stims); | |
| $display("Errors: %d", num_errors); | |
| $stop(); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module popcount_tb; | |
| logic data_w1; | |
| logic popcount_w1; | |
| logic [4:0] data_w5; | |
| logic [3:0] popcount_w5; | |
| logic [15:0] data_w16; | |
| logic [4:0] popcount_w16; | |
| logic [31:0] data_w32; | |
| logic [5:0] popcount_w32; | |
| logic [63:0] data_w64; | |
| logic [6:0] popcount_w64; | |
| logic [980:0] data_w981; | |
| logic [10:0] popcount_w981; | |
| popcount #(.INPUT_WIDTH(1)) i_popcount_w1 | |
| (.data_i(data_w1), | |
| .popcount_o(popcount_w1)); | |
| popcount #(.INPUT_WIDTH(5)) i_popcount_w5 | |
| (.data_i(data_w5), | |
| .popcount_o(popcount_w5)); | |
| popcount #(.INPUT_WIDTH(16)) i_popcount_w16 | |
| (.data_i(data_w16), | |
| .popcount_o(popcount_w16)); | |
| popcount #(.INPUT_WIDTH(32)) i_popcount_w32 | |
| (.data_i(data_w32), | |
| .popcount_o(popcount_w32)); | |
| popcount #(.INPUT_WIDTH(64)) i_popcount_w64 | |
| (.data_i(data_w64), | |
| .popcount_o(popcount_w64)); | |
| popcount #(.INPUT_WIDTH(981)) i_popcount_w981 | |
| (.data_i(data_w981), | |
| .popcount_o(popcount_w981)); | |
| initial begin | |
| data_w1 = 0; | |
| for(int i = 0; i<100; i++) | |
| begin | |
| do begin | |
| if (!(randomize(data_w1))) begin | |
| $display("%s:%0d: Randomization failed \"%s\"", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/popcount_tb.sv", 86, "randomize(data_w1)"); | |
| $finish; | |
| end | |
| end while (0); | |
| #5ns; | |
| assert(popcount_w1 == $countones(data_w1)) else $error("Popcount of %b was %d but should be %d.", data_w1, popcount_w1, $countones(data_w1)); | |
| end | |
| data_w5 = 0; | |
| #5ns; | |
| assert(popcount_w5 == $countones(data_w5)) else $error("Popcount of %b was %d but should be %d.", data_w5, popcount_w5, $countones(data_w5)); | |
| data_w5 = 1; | |
| #5ns; | |
| assert(popcount_w5 == $countones(data_w5)) else $error("Popcount of %b was %d but should be %d.", data_w5, popcount_w5, $countones(data_w5)); | |
| data_w5 = '1; | |
| #5ns; | |
| assert(popcount_w5 == $countones(data_w5)) else $error("Popcount of %b was %d but should be %d.", data_w5, popcount_w5, $countones(data_w5)); | |
| for(int i = 0; i<100; i++) | |
| begin | |
| do begin | |
| if (!(randomize(data_w5))) begin | |
| $display("%s:%0d: Randomization failed \"%s\"", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/popcount_tb.sv", 104, "randomize(data_w5)"); | |
| $finish; | |
| end | |
| end while (0); | |
| #5ns; | |
| assert(popcount_w5 == $countones(data_w5)) else $error("Popcount of %b was %d but should be %d.", data_w5, popcount_w5, $countones(data_w5)); | |
| end | |
| data_w16 = 0; | |
| #5ns; | |
| assert(popcount_w16 == $countones(data_w16)) else $error("Popcount of %b was %d but should be %d.", data_w16, popcount_w16, $countones(data_w16)); | |
| data_w16 = 1; | |
| #5ns; | |
| assert(popcount_w16 == $countones(data_w16)) else $error("Popcount of %b was %d but should be %d.", data_w16, popcount_w16, $countones(data_w16)); | |
| data_w16 = '1; | |
| #5ns; | |
| assert(popcount_w16 == $countones(data_w16)) else $error("Popcount of %b was %d but should be %d.", data_w16, popcount_w16, $countones(data_w16)); | |
| for(int i = 0; i<100; i++) | |
| begin | |
| do begin | |
| if (!(randomize(data_w16))) begin | |
| $display("%s:%0d: Randomization failed \"%s\"", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/popcount_tb.sv", 121, "randomize(data_w16)"); | |
| $finish; | |
| end | |
| end while (0); | |
| #5ns; | |
| assert(popcount_w16 == $countones(data_w16)) else $error("Popcount of %b was %d but should be %d.", data_w16, popcount_w16, $countones(data_w16)); | |
| end | |
| data_w32 = 0; | |
| #5ns; | |
| assert(popcount_w32 == $countones(data_w32)) else $error("Popcount of %b was %d but should be %d.", data_w32, popcount_w32, $countones(data_w32)); | |
| data_w32 = 1; | |
| #5ns; | |
| assert(popcount_w32 == $countones(data_w32)) else $error("Popcount of %b was %d but should be %d.", data_w32, popcount_w32, $countones(data_w32)); | |
| data_w32 = '1; | |
| #5ns; | |
| assert(popcount_w32 == $countones(data_w32)) else $error("Popcount of %b was %d but should be %d.", data_w32, popcount_w32, $countones(data_w32)); | |
| for(int i = 0; i<100; i++) | |
| begin | |
| do begin | |
| if (!(randomize(data_w32))) begin | |
| $display("%s:%0d: Randomization failed \"%s\"", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/popcount_tb.sv", 138, "randomize(data_w32)"); | |
| $finish; | |
| end | |
| end while (0); | |
| #5ns; | |
| assert(popcount_w32 == $countones(data_w32)) else $error("Popcount of %b was %d but should be %d.", data_w32, popcount_w32, $countones(data_w32)); | |
| end | |
| data_w64 = 0; | |
| #5ns; | |
| assert(popcount_w64 == $countones(data_w64)) else $error("Popcount of %b was %d but should be %d.", data_w64, popcount_w64, $countones(data_w64)); | |
| data_w64 = 1; | |
| #5ns; | |
| assert(popcount_w64 == $countones(data_w64)) else $error("Popcount of %b was %d but should be %d.", data_w64, popcount_w64, $countones(data_w64)); | |
| data_w64 = '1; | |
| #5ns; | |
| assert(popcount_w64 == $countones(data_w64)) else $error("Popcount of %b was %d but should be %d.", data_w64, popcount_w64, $countones(data_w64)); | |
| for(int i = 0; i<100; i++) | |
| begin | |
| do begin | |
| if (!(randomize(data_w64))) begin | |
| $display("%s:%0d: Randomization failed \"%s\"", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/popcount_tb.sv", 155, "randomize(data_w64)"); | |
| $finish; | |
| end | |
| end while (0); | |
| #5ns; | |
| assert(popcount_w64 == $countones(data_w64)) else $error("Popcount of %b was %d but should be %d.", data_w64, popcount_w64, $countones(data_w64)); | |
| end | |
| data_w981 = 0; | |
| #5ns; | |
| assert(popcount_w981 == $countones(data_w981)) else $error("Popcount of %b was %d but should be %d.", data_w981, popcount_w981, $countones(data_w981)); | |
| data_w981 = 1; | |
| #5ns; | |
| assert(popcount_w981 == $countones(data_w981)) else $error("Popcount of %b was %d but should be %d.", data_w981, popcount_w981, $countones(data_w981)); | |
| data_w981 = '1; | |
| #5ns; | |
| assert(popcount_w981 == $countones(data_w981)) else $error("Popcount of %b was %d but should be %d.", data_w981, popcount_w981, $countones(data_w981)); | |
| for(int i = 0; i<100; i++) | |
| begin | |
| do begin | |
| if (!(randomize(data_w981))) begin | |
| $display("%s:%0d: Randomization failed \"%s\"", "/home/mel/build/axi/.bender/git/checkouts/common_cells-3e2fcccecd7aee7b/test/popcount_tb.sv", 172, "randomize(data_w981)"); | |
| $finish; | |
| end | |
| end while (0); | |
| #5ns; | |
| assert(popcount_w981 == $countones(data_w981)) else $error("Popcount of %b was %d but should be %d.", data_w981, popcount_w981, $countones(data_w981)); | |
| end | |
| end | |
| endmodule : popcount_tb | |
| `begin_keywords "1800-2023" | |
| module rr_arb_tree_tb #( | |
| parameter int unsigned NumInp = 32'd7, | |
| parameter int unsigned NumReqs = 32'd20000, | |
| parameter bit AxiVldRdy = 1'b1, | |
| parameter bit LockIn = 1'b1, | |
| parameter bit FairArb = 1'b1 | |
| ); | |
| localparam time CyclTime = 10ns; | |
| localparam time ApplTime = 2ns; | |
| localparam time TestTime = 8ns; | |
| localparam real error_threshold = 0.1; | |
| localparam int unsigned IdxWidth = (NumInp > 32'd1) ? unsigned'($clog2(NumInp)) : 32'd1; | |
| localparam int unsigned DataWidth = 32'd45; | |
| typedef logic [IdxWidth-1:0] idx_t; | |
| typedef logic [DataWidth-1:0] data_t; | |
| logic clk; | |
| logic rst_n; | |
| logic flush; | |
| idx_t rr, idx; | |
| logic [NumInp-1:0] req_inp, gnt_inp, end_of_sim; | |
| data_t [NumInp-1:0] data_inp; | |
| logic req_oup, gnt_oup; | |
| data_t data_oup; | |
| clk_rst_gen #( | |
| .ClkPeriod ( CyclTime ), | |
| .RstClkCycles ( 5 ) | |
| ) i_clk_rst_gen ( | |
| .clk_o ( clk ), | |
| .rst_no ( rst_n ) | |
| ); | |
| for (genvar i = 0; i < NumInp; i++) begin : gen_stream_gen | |
| initial begin : proc_stream_gen | |
| automatic data_t stimuli; | |
| automatic int unsigned rand_wait; | |
| end_of_sim[i] = 1'b0; | |
| @(posedge rst_n); | |
| data_inp[i] = '0; | |
| req_inp[i] = 1'b0; | |
| for (int unsigned j = 0; j < (i+1) * NumReqs; j++) begin | |
| data_inp[i] <= #ApplTime data_t'(i); | |
| req_inp[i] <= #ApplTime 1'b1; | |
| @(posedge clk); | |
| end | |
| data_inp[i] <= #ApplTime '0; | |
| req_inp[i] <= #ApplTime 1'b0; | |
| repeat ((NumInp-i)*NumReqs) @(posedge clk); | |
| repeat (1000) @(posedge clk); | |
| for (int unsigned j = 0; j < (NumInp-i) * NumReqs; j++) begin | |
| data_inp[i] <= #ApplTime data_t'(i); | |
| req_inp[i] <= #ApplTime 1'b1; | |
| @(posedge clk); | |
| end | |
| data_inp[i] <= #ApplTime '0; | |
| req_inp[i] <= #ApplTime 1'b0; | |
| repeat ((1+i)*NumReqs) @(posedge clk); | |
| repeat (1000) @(posedge clk); | |
| for (int unsigned j = 0; j < (NumInp-i) * NumReqs; j++) begin | |
| if ((i % 2) == 0) begin | |
| data_inp[i] <= #ApplTime data_t'(i); | |
| req_inp[i] <= #ApplTime 1'b1; | |
| end | |
| @(posedge clk); | |
| end | |
| data_inp[i] <= #ApplTime '0; | |
| req_inp[i] <= #ApplTime 1'b0; | |
| repeat ((1+i)*NumReqs) @(posedge clk); | |
| repeat (1000) @(posedge clk); | |
| for (int unsigned j = 0; j < NumReqs; j++) begin | |
| data_inp[i] <= #ApplTime new_stimuli(); | |
| req_inp[i] <= #ApplTime 1'b1; | |
| rand_wait = $urandom_range(1, 2*NumInp); | |
| if (LockIn) begin | |
| #TestTime; | |
| while (!gnt_inp[i]) begin | |
| @(posedge clk); | |
| #TestTime; | |
| end | |
| end else begin | |
| repeat (rand_wait) @(posedge clk); | |
| end | |
| @(posedge clk); | |
| data_inp[i] <= #ApplTime '0; | |
| req_inp[i] <= #ApplTime 1'b0; | |
| rand_wait = $urandom_range(0, NumInp); | |
| repeat (rand_wait) @(posedge clk); | |
| end | |
| end_of_sim[i] = 1'b1; | |
| end | |
| end | |
| function data_t new_stimuli(); | |
| for (int unsigned i = 0; i < DataWidth; i++) begin | |
| new_stimuli[i] = $urandom(); | |
| end | |
| endfunction : new_stimuli | |
| initial begin : proc_stream_consume | |
| @(posedge rst_n); | |
| gnt_oup = 1'b0; | |
| forever begin | |
| gnt_oup <= #ApplTime 1'b1; | |
| @(posedge clk); | |
| end | |
| end | |
| initial begin : proc_flush | |
| automatic int unsigned rand_wait; | |
| flush = 1'b0; | |
| @(posedge rst_n); | |
| forever begin | |
| rand_wait = $urandom_range(2000, 20000); | |
| repeat (rand_wait) @(posedge clk); | |
| flush <= #ApplTime 1'b1; | |
| @(posedge clk); | |
| flush <= #ApplTime 1'b0; | |
| end | |
| end | |
| initial begin : proc_sim_end | |
| @(posedge rst_n); | |
| wait (&end_of_sim); | |
| repeat (10) @(posedge clk); | |
| $stop(); | |
| end | |
| for (genvar i = 0; i < NumInp; i++) begin : gen_throughput_checker | |
| initial begin : proc_throughput_checker | |
| automatic longint unsigned tot_active [NumInp:1]; | |
| automatic longint unsigned tot_served [NumInp:1]; | |
| automatic int unsigned num_active; | |
| automatic real throughput, exp_through, error; | |
| for (int unsigned j = 0; j < NumInp; j++) begin | |
| tot_active[j] = 0; | |
| tot_served[j] = 0; | |
| end | |
| @(posedge rst_n); | |
| while (!(&end_of_sim)) begin | |
| #TestTime; | |
| if (req_inp[i] && gnt_oup) begin | |
| num_active = 0; | |
| for (int unsigned j = 0; j < NumInp; j++) begin | |
| if (req_inp[j]) begin | |
| num_active++; | |
| end | |
| end | |
| tot_active[num_active] = tot_active[num_active] + 1; | |
| if (gnt_inp[i]) begin | |
| tot_served[num_active] = tot_served[num_active] + 1; | |
| end | |
| end | |
| @(posedge clk); | |
| end | |
| for (int unsigned j = 1; j <= NumInp; j++) begin | |
| if (tot_active[j] > 0) begin | |
| throughput = real'(tot_served[j])/real'(tot_active[j]); | |
| exp_through = real'(1)/real'(j); | |
| error = throughput - exp_through; | |
| if (FairArb && LockIn) begin | |
| assert(error < error_threshold && error > -error_threshold) else | |
| $warning("Line: %0d is unfair!", i); | |
| end | |
| $display("Line: %0d, TotActice: %0d Throughput: %0f Ideal: %0f Diff: %0f", | |
| i, j, throughput, exp_through, error); end | |
| end | |
| end | |
| end | |
| initial begin : proc_check_data | |
| automatic data_t data_queues[NumInp-1:0][$]; | |
| automatic data_t exp_data; | |
| forever begin | |
| @(posedge clk); | |
| #TestTime; | |
| for (int unsigned i = 0; i < NumInp; i++) begin | |
| if (req_inp[i] && gnt_inp[i]) begin | |
| data_queues[i].push_back(data_inp[i]); | |
| end | |
| end | |
| if (req_oup && gnt_oup) begin | |
| exp_data = data_queues[idx].pop_front(); | |
| assert(exp_data === data_oup); | |
| end | |
| end | |
| end | |
| rr_arb_tree #( | |
| .NumIn ( NumInp ), | |
| .DataWidth ( DataWidth ), | |
| .ExtPrio ( 1'b0 ), | |
| .AxiVldRdy ( AxiVldRdy ), | |
| .LockIn ( LockIn ), | |
| .FairArb ( FairArb ) | |
| ) i_rr_arb_tree_dut ( | |
| .clk_i ( clk ), | |
| .rst_ni ( rst_n ), | |
| .flush_i( flush ), | |
| .rr_i ( '0 ), | |
| .req_i ( req_inp ), | |
| .gnt_o ( gnt_inp ), | |
| .data_i ( data_inp ), | |
| .gnt_i ( gnt_oup ), | |
| .req_o ( req_oup ), | |
| .data_o ( data_oup ), | |
| .idx_o ( idx ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| package stream_test; | |
| class stream_driver #( | |
| parameter type payload_t = logic, | |
| parameter time TA = 2ns, | |
| parameter time TT = 8ns | |
| ); | |
| virtual STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) stream; | |
| function new ( | |
| virtual STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) stream | |
| ); | |
| this.stream = stream; | |
| endfunction | |
| function void reset_in(); | |
| stream.valid = 1'b0; | |
| endfunction | |
| function void reset_out(); | |
| stream.ready = 1'b0; | |
| endfunction | |
| task automatic cycle_start; | |
| #TT; | |
| endtask | |
| task automatic cycle_end; | |
| @(posedge stream.clk_i); | |
| endtask | |
| task automatic send (input payload_t data); | |
| stream.data <= #TA data; | |
| stream.valid <= #TA 1'b1; | |
| cycle_start(); | |
| while (stream.ready != 1) begin cycle_end(); cycle_start(); end | |
| cycle_end(); | |
| stream.valid <= #TA 1'b0; | |
| endtask | |
| task automatic recv(output payload_t data); | |
| stream.ready <= #TA 1'b1; | |
| cycle_start(); | |
| while (stream.valid != 1) begin cycle_end(); cycle_start(); end | |
| data = stream.data; | |
| cycle_end(); | |
| stream.ready <= #TA 1'b0; | |
| endtask | |
| endclass | |
| endpackage | |
| `begin_keywords "1800-2023" | |
| module stream_register_tb #( | |
| parameter type T = logic[7:0] | |
| ); | |
| logic clk, | |
| rst_n, | |
| clr, | |
| inp_valid, inp_ready, | |
| oup_valid, oup_ready; | |
| T inp_data, | |
| oup_data; | |
| int unsigned nr_checks; | |
| stream_register #( | |
| .T (T) | |
| ) dut ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .clr_i (clr), | |
| .testmode_i (1'b0), | |
| .valid_i (inp_valid), | |
| .ready_o (inp_ready), | |
| .data_i (inp_data), | |
| .valid_o (oup_valid), | |
| .ready_i (oup_ready), | |
| .data_o (oup_data) | |
| ); | |
| initial begin | |
| clk = 1'b0; | |
| rst_n = 1'b0; | |
| repeat(8) | |
| #10ns clk = ~clk; | |
| rst_n = 1'b1; | |
| forever | |
| #10ns clk = ~clk; | |
| end | |
| initial begin | |
| #100ms | |
| $display("Checked %d stimuli", nr_checks); | |
| $stop; | |
| end | |
| class random_action_t; | |
| rand logic [1:0] action; | |
| constraint random_action { | |
| action dist { | |
| 0 := 40, | |
| 1 := 40, | |
| 3 := 2, | |
| 0 := 0 | |
| }; | |
| } | |
| endclass | |
| logic[7:0] queue [$]; | |
| clocking cb @(posedge clk); | |
| default input #2 output #4; | |
| output clr, inp_data, inp_valid, oup_ready; | |
| input inp_ready, oup_valid, oup_data; | |
| endclocking | |
| clocking pck @(posedge clk); | |
| default input #2 output #4; | |
| input clr, inp_data, inp_valid, inp_ready, oup_data, oup_valid, oup_ready; | |
| endclocking | |
| initial begin | |
| automatic random_action_t random_action = new(); | |
| cb.clr <= 1'b0; | |
| wait (rst_n == 1'b1); | |
| cb.inp_valid <= 1'b0; | |
| forever begin | |
| void'(random_action.randomize()); | |
| repeat($urandom_range(0, 8)) @(cb); | |
| case (random_action.action) | |
| 0: begin | |
| cb.inp_data <= $urandom_range(0,256); | |
| cb.inp_valid <= 1'b1; | |
| end | |
| 1: begin | |
| cb.clr <= 1'b0; | |
| cb.inp_data <= $urandom_range(0,256); | |
| cb.inp_valid <= 1'b0; | |
| end | |
| default: begin | |
| cb.clr <= 1'b1; | |
| cb.inp_valid <= 1'b0; | |
| @(cb); | |
| cb.clr <= 1'b0; | |
| end | |
| endcase | |
| end | |
| end | |
| initial begin | |
| wait (rst_n == 1'b1); | |
| forever begin | |
| @(cb) | |
| cb.oup_ready <= 1'b1; | |
| repeat($urandom_range(0, 8)) @(cb); | |
| cb.oup_ready <= 1'b0; | |
| end | |
| end | |
| initial begin | |
| automatic T data; | |
| nr_checks = 0; | |
| forever begin | |
| @(pck) | |
| if (pck.inp_valid && pck.inp_ready && !pck.clr) begin | |
| queue.push_back(pck.inp_data); | |
| end | |
| if (pck.oup_valid && pck.oup_ready) begin | |
| data = queue.pop_front(); | |
| assert(data == pck.oup_data) | |
| else $error("Mismatch, Expected: %0h Got %0h", data, pck.oup_data); | |
| nr_checks++; | |
| end | |
| if (pck.clr) begin | |
| queue = {}; | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_to_mem_tb #( | |
| parameter int unsigned NumReq = 32'd10000, | |
| parameter int unsigned BufDepth = 32'd1 | |
| ); | |
| localparam time CyclTime = 10ns; | |
| localparam time ApplTime = 2ns; | |
| localparam time TestTime = 8ns; | |
| typedef logic [15:0] payload_t; | |
| logic clk, rst_n, sim_done; | |
| payload_t req, resp, mem_req, mem_resp; | |
| logic req_valid, resp_valid, mem_req_valid, mem_resp_valid; | |
| logic req_ready, resp_ready, mem_req_ready; | |
| payload_t data_fifo[$]; | |
| initial begin : proc_stream_master | |
| automatic payload_t test_data; | |
| automatic int unsigned stall_cycles; | |
| @(posedge rst_n); | |
| req = '0; | |
| req_valid = '0; | |
| repeat (5) @(posedge clk); | |
| for (int unsigned i = 0; i < NumReq; i++) begin | |
| stall_cycles = $urandom_range(0, 5); | |
| repeat (stall_cycles) @(posedge clk); | |
| test_data = payload_t'($urandom()); | |
| data_fifo.push_back(test_data); | |
| req <= #ApplTime payload_t'(test_data); | |
| req_valid <= #ApplTime 1'b1; | |
| #TestTime; | |
| while (!req_ready) begin | |
| @(posedge clk); | |
| #TestTime; | |
| end | |
| @(posedge clk); | |
| req <= #ApplTime '0; | |
| req_valid <= #ApplTime 1'b0; | |
| end | |
| end | |
| initial begin : proc_stream_slave | |
| automatic int unsigned stall_cycles; | |
| automatic payload_t test_data; | |
| automatic int unsigned num_tested = 32'd0; | |
| sim_done = 0; | |
| @(posedge rst_n); | |
| resp_ready = '0; | |
| repeat (5) @(posedge clk); | |
| while (num_tested < NumReq) begin | |
| resp_ready <= #ApplTime $urandom(); | |
| #TestTime; | |
| if (resp_valid && resp_ready) begin | |
| test_data = data_fifo.pop_front(); | |
| assert(test_data === resp) else $error("test_data: %h, resp_data: %0h", test_data, resp); | |
| num_tested++; | |
| end | |
| @(posedge clk); | |
| end | |
| repeat (50) @(posedge clk); | |
| sim_done = 1'b1; | |
| end | |
| initial begin : proc_mem_reflect | |
| automatic payload_t reflect_fifo[$]; | |
| @(posedge rst_n); | |
| mem_req_ready = '0; | |
| mem_resp = '0; | |
| mem_resp_valid = '0; | |
| forever begin | |
| mem_req_ready <= #ApplTime $urandom(); | |
| #(CyclTime / 2); | |
| if (mem_req_valid && mem_req_ready) begin | |
| reflect_fifo.push_back(mem_req); | |
| fork | |
| begin | |
| if (BufDepth) begin | |
| repeat (BufDepth) @(posedge clk); | |
| #ApplTime; | |
| end | |
| mem_resp = reflect_fifo.pop_front(); | |
| mem_resp_valid = 1'b1; | |
| @(posedge clk); | |
| #(ApplTime / 2); | |
| mem_resp_valid = 1'b0; | |
| end | |
| join_none | |
| end | |
| @(posedge clk); | |
| end | |
| end | |
| initial begin : proc_sim_stop | |
| @(posedge rst_n); | |
| wait (sim_done); | |
| $stop(); | |
| end | |
| clk_rst_gen #( | |
| .ClkPeriod ( CyclTime ), | |
| .RstClkCycles ( 10 ) | |
| ) i_clk_rst_gen ( | |
| .clk_o ( clk ), | |
| .rst_no ( rst_n ) | |
| ); | |
| stream_to_mem #( | |
| .mem_req_t ( payload_t ), | |
| .mem_resp_t ( payload_t ), | |
| .BufDepth ( BufDepth ) | |
| ) i_stream_to_mem_dut ( | |
| .clk_i ( clk ), | |
| .rst_ni ( rst_n ), | |
| .req_i ( req ), | |
| .req_valid_i ( req_valid ), | |
| .req_ready_o ( req_ready ), | |
| .resp_o ( resp ), | |
| .resp_valid_o ( resp_valid ), | |
| .resp_ready_i ( resp_ready ), | |
| .mem_req_o ( mem_req ), | |
| .mem_req_valid_o ( mem_req_valid ), | |
| .mem_req_ready_i ( mem_req_ready ), | |
| .mem_resp_i ( mem_resp ), | |
| .mem_resp_valid_i ( mem_resp_valid ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module sub_per_hash_tb; | |
| localparam time TCycle = 10ns; | |
| localparam time TAppli = 2ns; | |
| localparam time TTest = 8ns; | |
| localparam longint unsigned MaxCycles = 64'd100000000; | |
| localparam int unsigned DataWidth = 32'd11; | |
| localparam int unsigned HashWidth = 32'd5; | |
| localparam int unsigned NoHashes = 32'd3; | |
| localparam int unsigned NoRounds = 32'd1; | |
| typedef logic [DataWidth-1:0] data_t; | |
| typedef logic [HashWidth-1:0] hash_t; | |
| typedef logic [2**HashWidth-1:0] onehot_hash_t; | |
| localparam cb_filter_pkg::cb_seed_t [NoHashes-1:0] Seeds = '{ | |
| '{PermuteSeed: 32'd299034753, XorSeed: 32'd4094834 }, | |
| '{PermuteSeed: 32'd19921030, XorSeed: 32'd995713 }, | |
| '{PermuteSeed: 32'd294388, XorSeed: 32'd65146511} | |
| }; | |
| logic clk; | |
| logic rst_n; | |
| data_t data; | |
| hash_t [NoHashes-1:0] hash; | |
| onehot_hash_t [NoHashes-1:0] onehot_hash; | |
| clk_rst_gen #( | |
| .ClkPeriod ( TCycle ), | |
| .RstClkCycles ( 1 ) | |
| ) i_clk_gen ( | |
| .clk_o ( clk ), | |
| .rst_no ( rst_n ) | |
| ); | |
| initial begin : shutdown_sim | |
| repeat (MaxCycles) @(posedge clk); | |
| $info("Stop, because max cycles was reached."); | |
| $stop(); | |
| end | |
| initial begin : stimulus | |
| set_data(0); | |
| @(posedge rst_n); | |
| repeat (10) @(posedge clk); | |
| for (longint unsigned i = 0; i < 2**DataWidth; i++) begin | |
| set_data(i); | |
| end | |
| repeat (10) @(posedge clk); | |
| $info("Stop, because all possible inputs were applied."); | |
| $stop(); | |
| end | |
| task cycle_start(); | |
| #TTest; | |
| endtask : cycle_start | |
| task cycle_end(); | |
| @(posedge clk); | |
| endtask : cycle_end | |
| task set_data (input longint unsigned nbr); | |
| data <= #TAppli data_t'(nbr); | |
| cycle_end(); | |
| endtask : set_data | |
| task init_signals(); | |
| data <= '0; | |
| endtask : init_signals | |
| for (genvar i = 0; i < NoHashes; i++) begin : gen_hash_dut | |
| sub_per_hash #( | |
| .InpWidth ( DataWidth ), | |
| .HashWidth ( HashWidth ), | |
| .NoRounds ( NoRounds ), | |
| .PermuteKey ( Seeds[i].PermuteSeed ), | |
| .XorKey ( Seeds[i].XorSeed ) | |
| ) i_hash ( | |
| .data_i ( data ), | |
| .hash_o ( hash[i] ), | |
| .hash_onehot_o ( onehot_hash[i] ) | |
| ); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module isochronous_crossing_tb #( | |
| parameter int unsigned NumReq = 32'd10000, | |
| parameter string DUT = "spill_register", | |
| parameter int unsigned TCK_SRC_MULT = 2, | |
| parameter int unsigned TCK_DST_MULT = 6 | |
| ); | |
| localparam time CyclTime = 10ns; | |
| logic src_clk, dst_clk; | |
| logic src_rst_n, dst_rst_n; | |
| logic sim_done; | |
| typedef logic [15:0] payload_t; | |
| payload_t data_fifo[$]; | |
| mailbox #(payload_t) data_mbx = new(); | |
| STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) dut_in ( | |
| .clk_i (src_clk) | |
| ); | |
| STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) dut_out ( | |
| .clk_i (dst_clk) | |
| ); | |
| typedef stream_test::stream_driver #( | |
| .payload_t (payload_t), | |
| .TA (TCK_SRC_MULT*CyclTime*0.2), | |
| .TT (TCK_SRC_MULT*CyclTime*0.8) | |
| ) stream_driver_in_t; | |
| typedef stream_test::stream_driver #( | |
| .payload_t (payload_t), | |
| .TA (TCK_DST_MULT*CyclTime*0.2), | |
| .TT (TCK_DST_MULT*CyclTime*0.8) | |
| ) stream_driver_out_t; | |
| stream_driver_in_t in_driver = new(dut_in); | |
| stream_driver_out_t out_driver = new(dut_out); | |
| int unsigned handshake_mst = 0; | |
| int unsigned handshake_slv = 0; | |
| initial begin : proc_stream_master | |
| automatic payload_t test_data; | |
| automatic int unsigned stall_cycles; | |
| in_driver.reset_in(); | |
| @(posedge src_rst_n); | |
| repeat (5) @(posedge src_clk); | |
| for (int unsigned i = 0; i < NumReq; i++) begin | |
| test_data = payload_t'($urandom()); | |
| stall_cycles = $urandom_range(0, 5); | |
| handshake_mst++; | |
| repeat (stall_cycles) @(posedge src_clk); | |
| in_driver.send(test_data); | |
| data_mbx.put(test_data); | |
| end | |
| end | |
| initial begin : proc_stream_slave | |
| automatic int unsigned stall_cycles; | |
| automatic payload_t expected, actual; | |
| automatic int unsigned num_tested = 32'd0; | |
| sim_done = 0; | |
| out_driver.reset_out(); | |
| @(posedge dst_rst_n); | |
| repeat (5) @(posedge dst_clk); | |
| while (num_tested < NumReq) begin | |
| stall_cycles = $urandom_range(0, 5); | |
| repeat (stall_cycles) @(posedge dst_clk); | |
| out_driver.recv(actual); | |
| data_mbx.get(expected); | |
| handshake_slv++; | |
| assert(expected === actual) else $error("expected: %h, actual: %0h", expected, actual); | |
| num_tested++; | |
| end | |
| repeat (50) @(posedge dst_clk); | |
| sim_done = 1'b1; | |
| assert(handshake_mst == handshake_slv) else $error("Amount of handshakes differed."); | |
| end | |
| initial begin : proc_sim_stop | |
| @(posedge src_rst_n); | |
| wait (sim_done); | |
| $stop(); | |
| end | |
| initial begin | |
| $display("Simulating %d", DUT); | |
| src_clk = 1'b0; | |
| dst_clk = 1'b0; | |
| forever begin | |
| fork | |
| forever begin | |
| src_clk = ~src_clk; | |
| #((CyclTime * TCK_SRC_MULT) / 2); | |
| end | |
| forever begin | |
| dst_clk = ~dst_clk; | |
| #((CyclTime * TCK_DST_MULT) / 2); | |
| end | |
| join | |
| end | |
| end | |
| initial begin | |
| static int unsigned rst_cnt = 0; | |
| src_rst_n = 1'b0; | |
| while (rst_cnt <= 10) begin | |
| @(posedge src_clk); | |
| rst_cnt++; | |
| end | |
| src_rst_n = 1'b1; | |
| end | |
| initial begin | |
| static int unsigned rst_cnt = 0; | |
| dst_rst_n = 1'b0; | |
| while (rst_cnt <= 10) begin | |
| @(posedge src_clk); | |
| rst_cnt++; | |
| end | |
| dst_rst_n = 1'b1; | |
| end | |
| if (DUT == "spill_register") begin | |
| isochronous_spill_register #( | |
| .T (payload_t) | |
| ) i_isochronous_spill_register ( | |
| .src_clk_i (dut_in.clk_i), | |
| .src_rst_ni (src_rst_n), | |
| .src_valid_i (dut_in.valid), | |
| .src_ready_o (dut_in.ready), | |
| .src_data_i (dut_in.data), | |
| .dst_clk_i (dut_out.clk_i), | |
| .dst_rst_ni (dst_rst_n), | |
| .dst_valid_o (dut_out.valid), | |
| .dst_ready_i (dut_out.ready), | |
| .dst_data_o (dut_out.data) | |
| ); | |
| end if (DUT == "4phase_handshake") begin | |
| isochronous_4phase_handshake | |
| isochronous_4phase_handshake ( | |
| .src_clk_i (dut_in.clk_i), | |
| .src_rst_ni (src_rst_n), | |
| .src_valid_i (dut_in.valid), | |
| .src_ready_o (dut_in.ready), | |
| .dst_clk_i (dut_out.clk_i), | |
| .dst_rst_ni (dst_rst_n), | |
| .dst_valid_o (dut_out.valid), | |
| .dst_ready_i (dut_out.ready) | |
| ); | |
| always_ff @(posedge dut_in.clk_i) | |
| if (dut_in.valid & dut_in.ready) | |
| dut_out.data <= dut_in.data; | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_omega_net_tb #( | |
| parameter int unsigned NumReq = 32'd20000, | |
| parameter int unsigned DutNumInp = 32'd10, | |
| parameter int unsigned DutNumOut = 32'd10, | |
| parameter int unsigned DutRadix = 32'd2, | |
| parameter bit DutSpillReg = 1'b0, | |
| parameter time CyclTime = 20ns | |
| ); | |
| localparam OutSelWidth = (DutNumOut > 32'd1) ? unsigned'($clog2(DutNumOut)) : 32'd1; | |
| localparam InpIdxWidth = (DutNumInp > 32'd1) ? unsigned'($clog2(DutNumInp)) : 32'd1; | |
| typedef logic [OutSelWidth-1:0] sel_t; | |
| typedef logic [InpIdxWidth-1:0] idx_t; | |
| typedef struct packed { | |
| logic [15:0] payload; | |
| idx_t index; | |
| } payload_t; | |
| logic clk; | |
| logic rst_n; | |
| logic flush; | |
| logic [DutNumInp-1:0] sim_done; | |
| assign flush = 1'b0; | |
| clk_rst_gen #( | |
| .ClkPeriod ( CyclTime ), | |
| .RstClkCycles ( 5 ) | |
| ) i_clk_rst_gen ( | |
| .clk_o ( clk ), | |
| .rst_no ( rst_n ) | |
| ); | |
| payload_t data_fifo [DutNumInp-1:0][DutNumOut-1:0][$]; | |
| typedef stream_test::stream_driver #( | |
| .payload_t (payload_t), | |
| .TA (CyclTime*0.2), | |
| .TT (CyclTime*0.8) | |
| ) stream_driver_in_t; | |
| typedef stream_test::stream_driver #( | |
| .payload_t (payload_t), | |
| .TA (CyclTime*0.2), | |
| .TT (CyclTime*0.8) | |
| ) stream_driver_out_t; | |
| payload_t [DutNumInp-1:0] inp_data; | |
| logic [DutNumInp-1:0] inp_valid, inp_ready; | |
| sel_t [DutNumInp-1:0] out_sel; | |
| for (genvar i = 0; i < DutNumInp; i++) begin : gen_inp | |
| STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) dut_in ( | |
| .clk_i (clk) | |
| ); | |
| assign inp_data[i] = dut_in.data; | |
| assign inp_valid[i] = dut_in.valid; | |
| assign dut_in.ready = inp_ready[i]; | |
| stream_driver_in_t in_driver = new(dut_in); | |
| initial begin : proc_source | |
| automatic payload_t data; | |
| automatic int unsigned wait_cycl; | |
| data.index = idx_t'(i); | |
| @(posedge rst_n); | |
| in_driver.reset_in(); | |
| out_sel[i] = 1'b0; | |
| sim_done[i] = 1'b0; | |
| for (int unsigned i_stim = 0; i_stim < (NumReq/DutNumInp); i_stim++) begin | |
| wait_cycl = $urandom_range(0, 5); | |
| repeat (wait_cycl) @(posedge clk); | |
| data.payload = $urandom(); | |
| out_sel[i] = sel_t'($urandom_range(0, DutNumOut-1)); | |
| data_fifo[i][out_sel[i]].push_back(data); | |
| in_driver.send(data); | |
| end | |
| sim_done[i] = 1'b1; | |
| end | |
| end | |
| payload_t [DutNumOut-1:0] out_data; | |
| logic [DutNumOut-1:0] out_valid, out_ready; | |
| idx_t [DutNumOut-1:0] out_idx; | |
| for (genvar j = 0; j < DutNumOut; j++) begin : gen_out | |
| STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) dut_out ( | |
| .clk_i (clk) | |
| ); | |
| assign dut_out.data = out_data[j]; | |
| assign dut_out.valid = out_valid[j]; | |
| assign out_ready[j] = dut_out.ready; | |
| stream_driver_out_t out_driver = new(dut_out); | |
| initial begin : proc_sink | |
| automatic payload_t data, exp; | |
| automatic int unsigned wait_cycl; | |
| @(posedge rst_n); | |
| out_driver.reset_out(); | |
| forever begin | |
| wait_cycl = $urandom_range(0, 5); | |
| repeat (wait_cycl) @(posedge clk); | |
| out_driver.recv(data); | |
| exp = data_fifo[out_idx[j]][j].pop_front(); | |
| assert(data == exp) else | |
| $error("Out %d: Payload data does not match. Observed: %0h Expected: %0h", j, data, exp); | |
| assert(data.index == out_idx[j]) else | |
| $error("Index in payload: %0d does not match idx_o[%0d]: %0d", data.index, j, out_idx[j]); | |
| end | |
| end | |
| end | |
| initial begin : proc_stop_sim | |
| @(posedge rst_n); | |
| wait (&sim_done); | |
| repeat (20) @(posedge clk); | |
| $display("Sim done."); | |
| $stop(); | |
| end | |
| stream_omega_net #( | |
| .NumInp ( DutNumInp ), | |
| .NumOut ( DutNumOut ), | |
| .payload_t ( payload_t ), | |
| .SpillReg ( DutSpillReg ), | |
| .Radix ( DutRadix ), | |
| .ExtPrio ( 1'b0 ), | |
| .AxiVldRdy ( 1'b1 ), | |
| .LockIn ( 1'b1 ) | |
| ) i_stream_omega_net_dut ( | |
| .clk_i ( clk ), | |
| .rst_ni ( rst_n ), | |
| .flush_i ( flush ), | |
| .rr_i ( '0 ), | |
| .data_i ( inp_data ), | |
| .sel_i ( out_sel ), | |
| .valid_i ( inp_valid ), | |
| .ready_o ( inp_ready ), | |
| .data_o ( out_data ), | |
| .idx_o ( out_idx ), | |
| .valid_o ( out_valid ), | |
| .ready_i ( out_ready ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module stream_xbar_tb #( | |
| parameter int unsigned NumReq = 32'd10000, | |
| parameter int unsigned NumInp = 32'd10, | |
| parameter int unsigned NumOut = 32'd10, | |
| parameter bit SpillReg = 1'b0, | |
| parameter time CyclTime = 20ns | |
| ); | |
| localparam OutSelWidth = (NumOut > 32'd1) ? unsigned'($clog2(NumOut)) : 32'd1; | |
| localparam InpIdxWidth = (NumInp > 32'd1) ? unsigned'($clog2(NumInp)) : 32'd1; | |
| typedef logic [OutSelWidth-1:0] sel_t; | |
| typedef logic [InpIdxWidth-1:0] idx_t; | |
| typedef struct packed { | |
| logic [15:0] payload; | |
| idx_t index; | |
| } payload_t; | |
| logic clk; | |
| logic rst_n; | |
| logic flush; | |
| logic [NumInp-1:0] sim_done; | |
| assign flush = 1'b0; | |
| clk_rst_gen #( | |
| .ClkPeriod ( CyclTime ), | |
| .RstClkCycles ( 5 ) | |
| ) i_clk_rst_gen ( | |
| .clk_o ( clk ), | |
| .rst_no ( rst_n ) | |
| ); | |
| payload_t data_fifo [NumInp-1:0][NumOut-1:0][$]; | |
| typedef stream_test::stream_driver #( | |
| .payload_t (payload_t), | |
| .TA (CyclTime*0.2), | |
| .TT (CyclTime*0.8) | |
| ) stream_driver_in_t; | |
| typedef stream_test::stream_driver #( | |
| .payload_t (payload_t), | |
| .TA (CyclTime*0.2), | |
| .TT (CyclTime*0.8) | |
| ) stream_driver_out_t; | |
| payload_t [NumInp-1:0] inp_data; | |
| logic [NumInp-1:0] inp_valid, inp_ready; | |
| sel_t [NumInp-1:0] out_sel; | |
| for (genvar i = 0; i < NumInp; i++) begin : gen_inp | |
| STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) dut_in ( | |
| .clk_i (clk) | |
| ); | |
| assign inp_data[i] = dut_in.data; | |
| assign inp_valid[i] = dut_in.valid; | |
| assign dut_in.ready = inp_ready[i]; | |
| stream_driver_in_t in_driver = new(dut_in); | |
| initial begin : proc_source | |
| automatic payload_t data; | |
| automatic int unsigned wait_cycl; | |
| data.index = idx_t'(i); | |
| @(posedge rst_n); | |
| in_driver.reset_in(); | |
| out_sel[i] = 1'b0; | |
| sim_done[i] = 1'b0; | |
| for (int unsigned i_stim = 0; i_stim < NumReq; i_stim++) begin | |
| wait_cycl = $urandom_range(0, 5); | |
| repeat (wait_cycl) @(posedge clk); | |
| data.payload = $urandom(); | |
| out_sel[i] = sel_t'($urandom_range(0, NumOut-1)); | |
| data_fifo[i][out_sel[i]].push_back(data); | |
| in_driver.send(data); | |
| end | |
| sim_done[i] = 1'b1; | |
| end | |
| end | |
| payload_t [NumOut-1:0] out_data; | |
| logic [NumOut-1:0] out_valid, out_ready; | |
| idx_t [NumOut-1:0] out_idx; | |
| for (genvar j = 0; j < NumOut; j++) begin : gen_out | |
| STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) dut_out ( | |
| .clk_i (clk) | |
| ); | |
| assign dut_out.data = out_data[j]; | |
| assign dut_out.valid = out_valid[j]; | |
| assign out_ready[j] = dut_out.ready; | |
| stream_driver_out_t out_driver = new(dut_out); | |
| initial begin : proc_sink | |
| automatic payload_t data, exp; | |
| automatic int unsigned wait_cycl; | |
| @(posedge rst_n); | |
| out_driver.reset_out(); | |
| forever begin | |
| wait_cycl = $urandom_range(0, 5); | |
| repeat (wait_cycl) @(posedge clk); | |
| out_driver.recv(data); | |
| exp = data_fifo[out_idx[j]][j].pop_front(); | |
| assert(data == exp) else | |
| $error("Out %d: Payload data does not match. Observed: %0h Expected: %0h", j, data, exp); | |
| assert(data.index == out_idx[j]) else | |
| $error("Index in payload: %0d does not match idx_o[%0d]: %0d", data.index, j, out_idx[j]); | |
| end | |
| end | |
| end | |
| initial begin : proc_stop_sim | |
| @(posedge rst_n); | |
| wait (&sim_done); | |
| repeat (20) @(posedge clk); | |
| $display("Sim done."); | |
| $stop(); | |
| end | |
| stream_xbar #( | |
| .NumInp ( NumInp ), | |
| .NumOut ( NumOut ), | |
| .payload_t ( payload_t ), | |
| .OutSpillReg ( SpillReg ), | |
| .ExtPrio ( 1'b0 ), | |
| .AxiVldRdy ( 1'b1 ), | |
| .LockIn ( 1'b1 ) | |
| ) i_stream_xbar_dut ( | |
| .clk_i ( clk ), | |
| .rst_ni ( rst_n ), | |
| .flush_i ( flush ), | |
| .rr_i ( '0 ), | |
| .data_i ( inp_data ), | |
| .sel_i ( out_sel ), | |
| .valid_i ( inp_valid ), | |
| .ready_o ( inp_ready ), | |
| .data_o ( out_data ), | |
| .idx_o ( out_idx ), | |
| .valid_o ( out_valid ), | |
| .ready_i ( out_ready ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module clk_int_div_tb; | |
| import stream_test::*; | |
| parameter int unsigned NumTests = 10000; | |
| parameter time TClkIn = 10ns; | |
| parameter int DivWidth = 3; | |
| parameter int MaxWaitCycles = 20; | |
| localparam time t_delta = 1ns; | |
| localparam int unsigned RstClkCycles = 10; | |
| localparam time TA = TClkIn*0.2; | |
| localparam time TT = TClkIn*0.8; | |
| localparam clock_disable_probability = 5; | |
| logic clk, rstn; | |
| logic test_mode_en; | |
| logic enable; | |
| logic clk_out; | |
| semaphore semphr_is_transitioning; | |
| bit is_transitioning = 1'b0; | |
| int wait_cycl; | |
| time target_tclk_half_max; | |
| time target_tclk_half_min; | |
| logic [DivWidth-1:0] current_div_value; | |
| logic [DivWidth-1:0] next_div_value; | |
| time last_rising_edge; | |
| time last_falling_edge; | |
| int error_count = 0; | |
| typedef logic [DivWidth-1:0] payload_t; | |
| let max(a,b) = (a > b) ? a : b; | |
| let min(a,b) = (a < b) ? a : b; | |
| typedef stream_test::stream_driver #( | |
| .payload_t (payload_t), | |
| .TA (TA), | |
| .TT (TT) | |
| ) stream_driver_t; | |
| STREAM_DV #( | |
| .payload_t (payload_t) | |
| ) dut_in ( | |
| .clk_i (clk) | |
| ); | |
| stream_driver_t in_driver = new(dut_in); | |
| clk_rst_gen #( | |
| .ClkPeriod ( TClkIn ), | |
| .RstClkCycles ( RstClkCycles ) | |
| ) i_clk_rst_gen_reg ( | |
| .clk_o ( clk ), | |
| .rst_no ( rstn ) | |
| ); | |
| clk_int_div #( | |
| .DIV_VALUE_WIDTH(DivWidth) | |
| ) i_dut( | |
| .clk_i ( clk ), | |
| .rst_ni ( rstn ), | |
| .en_i ( enable ), | |
| .test_mode_en_i ( test_mode_en ), | |
| .div_i ( dut_in.data ), | |
| .div_valid_i ( dut_in.valid ), | |
| .div_ready_o ( dut_in.ready ), | |
| .clk_o ( clk_out ), | |
| .cycl_count_o ( ) | |
| ); | |
| initial begin : apply_stimuli | |
| semphr_is_transitioning = new(); | |
| test_mode_en = 1'b0; | |
| enable = 1'b1; | |
| next_div_value = 1; | |
| current_div_value = 1; | |
| $info("Resetting clock divider..."); | |
| @(posedge rstn); | |
| in_driver.reset_in(); | |
| test_mode_en = 1'b1; | |
| semphr_is_transitioning.put(); | |
| repeat (100) @(clk); | |
| test_mode_en = 1'b0; | |
| $info("Testing programming divider while clock disabled..."); | |
| enable = 1'b0; | |
| next_div_value = 3; | |
| semphr_is_transitioning.put(1); | |
| wait_cycl = $urandom_range(5*current_div_value, MaxWaitCycles*current_div_value); | |
| repeat(wait_cycl) @(posedge clk); | |
| in_driver.send(next_div_value); | |
| current_div_value = next_div_value; | |
| semphr_is_transitioning.put(1); | |
| @(posedge clk); | |
| enable = 1'b1; | |
| repeat(20) @(posedge clk); | |
| $info("Starting randomized reconfiguration while clock is enabled..."); | |
| for (int i = 0; i < NumTests; i++) begin | |
| logic [DivWidth-1:0] div_value_temp; | |
| assert(std::randomize(div_value_temp)) else | |
| $error("Randomization failure"); | |
| $info("Setting clock divider value to %0d", next_div_value); | |
| next_div_value = (div_value_temp == 0)? 1: div_value_temp; | |
| in_driver.send(div_value_temp); | |
| semphr_is_transitioning.put(1); | |
| current_div_value = next_div_value; | |
| wait_cycl = $urandom_range(0, MaxWaitCycles); | |
| repeat(wait_cycl) @(posedge clk_out); | |
| if ($urandom_range(0, 100) < clock_disable_probability) begin | |
| repeat(4) @(posedge clk_out); | |
| enable = 1'b0; | |
| semphr_is_transitioning.put(1); | |
| wait_cycl = $urandom_range(5*current_div_value, MaxWaitCycles*current_div_value); | |
| repeat(wait_cycl) @(posedge clk); | |
| enable = 1'b1; | |
| repeat(wait_cycl) @(posedge clk_out); | |
| end | |
| end | |
| $info("Test finished"); | |
| $info("Total error count: %0d", error_count); | |
| $stop(); | |
| end | |
| initial begin : check_clock | |
| last_rising_edge = $realtime(); | |
| last_falling_edge = $realtime(); | |
| target_tclk_half_max = TClkIn+t_delta; | |
| target_tclk_half_min = TClkIn-t_delta; | |
| @(posedge rstn); | |
| forever begin | |
| @(posedge clk_out); | |
| is_transitioning = semphr_is_transitioning.try_get(1); | |
| if (is_transitioning) begin | |
| target_tclk_half_max = TClkIn*max(current_div_value, next_div_value)/2+t_delta; | |
| target_tclk_half_min = TClkIn*min(current_div_value, next_div_value)/2-t_delta; | |
| end else begin | |
| target_tclk_half_max = TClkIn*current_div_value/2+t_delta; | |
| target_tclk_half_min = TClkIn*current_div_value/2-t_delta; | |
| assert($realtime()-last_falling_edge < target_tclk_half_max) else begin | |
| $error("Detected wrong duty cycle. Target t_low period should be lower than %0t ns but was %0t ns", target_tclk_half_max, $realtime()-last_falling_edge); | |
| error_count++; | |
| end | |
| end | |
| assert($realtime()-last_falling_edge > target_tclk_half_min) else begin | |
| $error("Detected clock glitch. Last low period was to short (%0t ns < %0t ns).", $realtime()-last_falling_edge, target_tclk_half_min); | |
| error_count++; | |
| end | |
| last_rising_edge = $realtime(); | |
| @(negedge clk_out); | |
| assert($realtime()-last_rising_edge > target_tclk_half_min) else begin | |
| $error("Detected wrong duty cycle. Last high period was to short (%0t ns < %0t ns).", $realtime()-last_rising_edge, target_tclk_half_min); | |
| error_count++; | |
| end | |
| assert($realtime()-last_rising_edge < target_tclk_half_max) else begin | |
| $error("Detected wrong duty cycle. Last high period was to long (%0t ns > %0t ns).", $realtime()-last_rising_edge, target_tclk_half_max); | |
| error_count++; | |
| end | |
| last_falling_edge = $realtime(); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module clk_int_div_static_tb; | |
| parameter int unsigned NumTestCycles = 10000; | |
| parameter realtime TClkIn = 10ns; | |
| localparam int unsigned RstClkCycles = 10; | |
| localparam int unsigned MaxClkDiv = 100; | |
| realtime t_delta = 100ps; | |
| logic clk, rstn; | |
| logic test_mode_en; | |
| logic enable; | |
| logic clk_out [MaxClkDiv]; | |
| clk_rst_gen #( | |
| .ClkPeriod ( TClkIn ), | |
| .RstClkCycles ( RstClkCycles ) | |
| ) i_clk_rst_gen_reg ( | |
| .clk_o ( clk ), | |
| .rst_no ( rstn ) | |
| ); | |
| for (genvar i = 1; i < MaxClkDiv; i++) begin :gen_clk_divs | |
| clk_int_div_static #( | |
| .DIV_VALUE(i), | |
| .ENABLE_CLOCK_IN_RESET(1'b1) | |
| ) i_dut( | |
| .clk_i ( clk ), | |
| .rst_ni ( rstn ), | |
| .en_i ( enable ), | |
| .test_mode_en_i ( test_mode_en ), | |
| .clk_o ( clk_out[i] ) | |
| ); | |
| end | |
| initial begin : apply_stimuli | |
| test_mode_en = 1'b0; | |
| enable = 1'b1; | |
| $info("Resetting clock dividers..."); | |
| @(posedge rstn); | |
| repeat(NumTestCycles) begin | |
| @(posedge clk); | |
| if ($urandom_range(0, 1000)<5) begin | |
| enable = 1'b0; | |
| repeat($urandom_range(1, 100)) @(posedge clk); | |
| enable = 1'b1; | |
| end | |
| end | |
| $info("Test finished"); | |
| $stop(); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module clk_mux_glitch_free_tb; | |
| timeunit 1ns; | |
| timeprecision 1ps; | |
| parameter int unsigned NUM_INPUTS = 10; | |
| localparam int unsigned SEL_WIDTH = $clog2(NUM_INPUTS); | |
| parameter realtime MIN_PERIOD = 1ns; | |
| parameter realtime MAX_PERIOD = 3ns; | |
| parameter realtime TIME_RESOLUTION = 0.1ns; | |
| parameter int TEST_LENGTH = 1000; | |
| logic [SEL_WIDTH-1:0] s_sel = '0; | |
| logic [NUM_INPUTS-1:0] s_clocks = '0; | |
| logic s_rstn; | |
| logic s_clock_output; | |
| realtime target_periods [NUM_INPUTS-1:0]; | |
| int num_errors = 0; | |
| task automatic delay_random(input realtime min_delay, input realtime max_delay); | |
| int delay_int = $urandom_range($rtoi(min_delay/TIME_RESOLUTION), $rtoi(max_delay/TIME_RESOLUTION)); | |
| repeat(delay_int) #TIME_RESOLUTION; | |
| endtask | |
| for (genvar i = 0; i < NUM_INPUTS; i++) begin : gen_clocks | |
| initial begin : clock_gen | |
| automatic int period_int; | |
| period_int = $urandom_range($rtoi(MIN_PERIOD/TIME_RESOLUTION), $rtoi(MAX_PERIOD/TIME_RESOLUTION)); | |
| target_periods[i] = period_int * TIME_RESOLUTION; | |
| delay_random(0, MAX_PERIOD); | |
| forever begin | |
| s_clocks[i] = 1'b1; | |
| repeat(period_int/2) #(TIME_RESOLUTION); | |
| s_clocks[i] = 1'b0; | |
| repeat(period_int/2) #(TIME_RESOLUTION); | |
| end | |
| end | |
| end | |
| initial begin : stimulate_sel_input | |
| $info("Starting Test"); | |
| $info("Asserting hard reset"); | |
| s_rstn = 1'b0; | |
| s_sel = $urandom_range(0, NUM_INPUTS-1); | |
| delay_random(0, MAX_PERIOD*1000); | |
| $info("Deasserting hard reset."); | |
| s_rstn = 1'b1; | |
| $info("Switching between clock inputs %0d times", TEST_LENGTH); | |
| for (int i = 0; i < TEST_LENGTH; i++) begin | |
| delay_random(MAX_PERIOD*10, MAX_PERIOD*30); | |
| s_sel = $urandom_range(0, NUM_INPUTS-1); | |
| end | |
| repeat(10) @(posedge s_clock_output); | |
| $info("Test finished with %0d errors.", num_errors); | |
| $stop(); | |
| end | |
| initial begin : check_clock | |
| automatic realtime last_high_pulse_duration = 0ns; | |
| automatic realtime last_low_pulse_duration = 0ns; | |
| automatic realtime pulse_duraton = 0ns; | |
| automatic realtime last_edge = 0ns; | |
| $timeformat(-9, 3, "ns", 0); | |
| forever begin | |
| @(posedge s_clock_output); | |
| pulse_duraton = $realtime - last_edge; | |
| if ((((last_low_pulse_duration - pulse_duraton) < 0 )? -(last_low_pulse_duration - pulse_duraton) : (last_low_pulse_duration - pulse_duraton)) > TIME_RESOLUTION) begin | |
| assert(pulse_duraton + TIME_RESOLUTION >= target_periods[s_sel]/2) else | |
| $error("Error #%0d: Clock low pulse duration was %t but should be larger than %t", num_errors++, pulse_duraton, target_periods[s_sel]/2); | |
| end | |
| last_edge = $realtime; | |
| last_low_pulse_duration = pulse_duraton; | |
| @(negedge s_clock_output); | |
| pulse_duraton = $realtime - last_edge; | |
| if ((((last_high_pulse_duration - pulse_duraton) < 0 )? -(last_high_pulse_duration - pulse_duraton) : (last_high_pulse_duration - pulse_duraton)) > TIME_RESOLUTION) begin | |
| assert( (((pulse_duraton - target_periods[s_sel]/2) < 0 )? -(pulse_duraton - target_periods[s_sel]/2) : (pulse_duraton - target_periods[s_sel]/2)) <= TIME_RESOLUTION) else | |
| $error("Error #%0d: Clock high pulse duration was %t but should be equal to %t", num_errors++, pulse_duraton, target_periods[s_sel]/2); | |
| end | |
| last_edge = $realtime; | |
| last_high_pulse_duration = pulse_duraton; | |
| end | |
| end | |
| clk_mux_glitch_free #( | |
| .NUM_INPUTS(NUM_INPUTS) | |
| ) i_dut ( | |
| .clks_i ( s_clocks ), | |
| .test_clk_i ( 1'b0 ), | |
| .test_en_i ( 1'b0 ), | |
| .async_rstn_i ( s_rstn ), | |
| .async_sel_i ( s_sel ), | |
| .clk_o ( s_clock_output ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module lossy_valid_to_stream_tb #( | |
| parameter int unsigned NumReq = 32'd10000, | |
| parameter time CyclTime = 20ns | |
| ); | |
| logic clk; | |
| logic rst_n; | |
| localparam type payload_t = logic [$clog2(NumReq)-1:0]; | |
| clk_rst_gen #( | |
| .ClkPeriod (CyclTime), | |
| .RstClkCycles(5) | |
| ) i_clk_rst_gen ( | |
| .clk_o (clk), | |
| .rst_no(rst_n) | |
| ); | |
| typedef stream_test::stream_driver#( | |
| .payload_t(payload_t), | |
| .TA(CyclTime * 0.2), | |
| .TT(CyclTime * 0.8) | |
| ) stream_driver_in_t; | |
| STREAM_DV #(.payload_t(payload_t)) dut_in (.clk_i(clk)); | |
| stream_driver_in_t stream_source = new(dut_in); | |
| typedef stream_test::stream_driver#( | |
| .payload_t(payload_t), | |
| .TA(CyclTime * 0.2), | |
| .TT(CyclTime * 0.8) | |
| ) stream_driver_out_t; | |
| STREAM_DV #(.payload_t(payload_t)) dut_out (.clk_i(clk)); | |
| stream_driver_out_t stream_sink = new(dut_out); | |
| payload_t payload_queue[$]; | |
| logic is_busy; | |
| assign dut_in.ready = 1'b1; | |
| lossy_valid_to_stream #( | |
| .T(payload_t) | |
| ) i_lossy_valid_to_stream ( | |
| .clk_i (clk), | |
| .rst_ni (rst_n), | |
| .valid_i(dut_in.valid), | |
| .data_i (dut_in.data), | |
| .data_o (dut_out.data), | |
| .valid_o(dut_out.valid), | |
| .ready_i(dut_out.ready), | |
| .busy_o(is_busy) | |
| ); | |
| initial begin : apply_stimuli | |
| automatic int unsigned wait_cycl; | |
| @(posedge rst_n); | |
| stream_source.reset_in(); | |
| for (int i = 0; i < NumReq; i++) begin | |
| wait_cycl = $urandom_range(0, 5); | |
| repeat (wait_cycl) @(posedge clk); | |
| stream_source.send(i); | |
| if (payload_queue.size() == 2 && !dut_out.ready) | |
| payload_queue[0] = i; | |
| else | |
| payload_queue.push_front(i); | |
| end | |
| $stop(); | |
| end | |
| initial begin : receive_responses | |
| automatic payload_t data; | |
| automatic payload_t expected_data; | |
| automatic int unsigned wait_cycl; | |
| @(posedge rst_n); | |
| stream_sink.reset_out(); | |
| forever begin | |
| wait_cycl = $urandom_range(0, 5); | |
| repeat (wait_cycl) @(posedge clk); | |
| stream_sink.recv(data); | |
| assert (payload_queue.size() > 0) else | |
| $error("Receieved transaction at output even though the input side did not send any new data."); | |
| expected_data = payload_queue.pop_back(); | |
| assert (data == expected_data) else | |
| $error("Received the wrong data.x Was %d instead of %d", data, expected_data); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module clock_divider_counter | |
| #( | |
| parameter BYPASS_INIT = 1, | |
| parameter DIV_INIT = 'hFF | |
| ) | |
| ( | |
| input logic clk, | |
| input logic rstn, | |
| input logic test_mode, | |
| input logic [7:0] clk_div, | |
| input logic clk_div_valid, | |
| output logic clk_out | |
| ); | |
| logic [7:0] counter; | |
| logic [7:0] counter_next; | |
| logic [7:0] clk_cnt; | |
| logic en1; | |
| logic en2; | |
| logic is_odd; | |
| logic div1; | |
| logic div2; | |
| logic div2_neg_sync; | |
| logic [7:0] clk_cnt_odd; | |
| logic [7:0] clk_cnt_odd_incr; | |
| logic [7:0] clk_cnt_even; | |
| logic [7:0] clk_cnt_en2; | |
| logic bypass; | |
| logic clk_out_gen; | |
| logic clk_div_valid_reg; | |
| logic clk_inv_test; | |
| logic clk_inv; | |
| assign clk_cnt_odd = clk_div - 8'h1; | |
| assign clk_cnt_even = (clk_div == 8'h2) ? 8'h0 : ({1'b0,clk_div[7:1]} - 8'h1); | |
| assign clk_cnt_en2 = {1'b0,clk_cnt[7:1]} + 8'h1; | |
| always_comb | |
| begin | |
| if (counter == 'h0) | |
| en1 = 1'b1; | |
| else | |
| en1 = 1'b0; | |
| if (clk_div_valid) | |
| counter_next = 'h0; | |
| else if (counter == clk_cnt) | |
| counter_next = 'h0; | |
| else | |
| counter_next = counter + 1; | |
| if (clk_div_valid) | |
| en2 = 1'b0; | |
| else if (counter == clk_cnt_en2) | |
| en2 = 1'b1; | |
| else | |
| en2 = 1'b0; | |
| end | |
| always_ff @(posedge clk, negedge rstn) | |
| begin | |
| if (~rstn) | |
| begin | |
| counter <= 'h0; | |
| div1 <= 1'b0; | |
| bypass <= BYPASS_INIT; | |
| clk_cnt <= DIV_INIT; | |
| is_odd <= 1'b0; | |
| clk_div_valid_reg <= 1'b0; | |
| end | |
| else | |
| begin | |
| if (!bypass) | |
| counter <= counter_next; | |
| clk_div_valid_reg <= clk_div_valid; | |
| if (clk_div_valid) | |
| begin | |
| if ((clk_div == 8'h0) || (clk_div == 8'h1)) | |
| begin | |
| bypass <= 1'b1; | |
| clk_cnt <= 'h0; | |
| is_odd <= 1'b0; | |
| end | |
| else | |
| begin | |
| bypass <= 1'b0; | |
| if (clk_div[0]) | |
| begin | |
| is_odd <= 1'b1; | |
| clk_cnt <= clk_cnt_odd; | |
| end | |
| else | |
| begin | |
| is_odd <= 1'b0; | |
| clk_cnt <= clk_cnt_even; | |
| end | |
| end | |
| div1 <= 1'b0; | |
| end | |
| else | |
| begin | |
| if (en1 && !bypass) | |
| div1 <= ~div1; | |
| end | |
| end | |
| end | |
| pulp_clock_inverter clk_inv_i | |
| ( | |
| .clk_i(clk), | |
| .clk_o(clk_inv) | |
| ); | |
| assign clk_inv_test = clk_inv; | |
| always_ff @(posedge clk_inv_test or negedge rstn) | |
| begin | |
| if (!rstn) | |
| begin | |
| div2 <= 1'b0; | |
| end | |
| else | |
| begin | |
| if (clk_div_valid_reg) | |
| div2 <= 1'b0; | |
| else if (en2 && is_odd && !bypass) | |
| div2 <= ~div2; | |
| end | |
| end | |
| pulp_clock_xor2 clock_xor_i | |
| ( | |
| .clk_o(clk_out_gen), | |
| .clk0_i(div1), | |
| .clk1_i(div2) | |
| ); | |
| pulp_clock_mux2 clk_mux_i | |
| ( | |
| .clk0_i(clk_out_gen), | |
| .clk1_i(clk), | |
| .clk_sel_i(bypass || test_mode), | |
| .clk_o(clk_out) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module clk_div #( | |
| parameter int unsigned RATIO = 4, | |
| parameter bit SHOW_WARNING = 1'b1 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic testmode_i, | |
| input logic en_i, | |
| output logic clk_o | |
| ); | |
| logic [RATIO-1:0] counter_q; | |
| logic clk_q; | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (~rst_ni) begin | |
| clk_q <= 1'b0; | |
| counter_q <= '0; | |
| end else begin | |
| clk_q <= 1'b0; | |
| if (en_i) begin | |
| if (counter_q == (RATIO[RATIO-1:0] - 1)) begin | |
| clk_q <= 1'b1; | |
| end else begin | |
| counter_q <= counter_q + 1; | |
| end | |
| end | |
| end | |
| end | |
| assign clk_o = testmode_i ? clk_i : clk_q; | |
| if (SHOW_WARNING) begin : gen_elab_warning | |
| $warning( | |
| "This clock divider is deprecated and not reccomended since ", | |
| "the generated output clock has a very unbalanced duty cycle ", | |
| "(1/RATIO). For new designs we reccomend using the at-runtime ", | |
| "configurable clk_int_div module which always generates 50%% ", | |
| "duty cycle clock. If you don't need at runtime configuration ", | |
| "support, you can instantiate clk_int_div as follows to ", | |
| "obtain a module with roughly the same behavior (except for ", | |
| "the 50 %% duty cycle):\n ", | |
| "\n ", | |
| " clk_int_div #(\n ", | |
| " .DIV_VALUE_WIDTH($clog2(RATIO+1)),\n ", | |
| " .DEFAULT_DIV_VALUE(RATIO)\n ", | |
| " ) i_clk_int_div(\n ", | |
| " .clk_i,\n ", | |
| " .rst_ni,\n ", | |
| " .test_mode_en_i(testmode_i),\n ", | |
| " .en_i,\n ", | |
| " .div_i('1), // Ignored, used default value\n ", | |
| " .div_valid_i(1'b0),\n ", | |
| " .div_ready_o(),\n ", | |
| " .clk_o\n ", | |
| " ); ", | |
| "\n ", | |
| "If you know what your are doing and want to disable this ", | |
| "warning message, you can disable it by overriding the new ", | |
| "optional clk_div parameter SHOW_WARNING to 1'b0."); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module find_first_one #( | |
| parameter int WIDTH = -1, | |
| parameter int FLIP = 0 | |
| )( | |
| input logic [WIDTH-1:0] in_i, | |
| output logic [$clog2(WIDTH)-1:0] first_one_o, | |
| output logic no_ones_o | |
| ); | |
| localparam int NUM_LEVELS = $clog2(WIDTH); | |
| initial begin | |
| assert(WIDTH >= 0); | |
| end | |
| logic [WIDTH-1:0][NUM_LEVELS-1:0] index_lut; | |
| logic [2**NUM_LEVELS-1:0] sel_nodes; | |
| logic [2**NUM_LEVELS-1:0][NUM_LEVELS-1:0] index_nodes; | |
| logic [WIDTH-1:0] in_tmp; | |
| for (genvar i = 0; i < WIDTH; i++) begin | |
| assign in_tmp[i] = FLIP ? in_i[WIDTH-1-i] : in_i[i]; | |
| end | |
| for (genvar j = 0; j < WIDTH; j++) begin | |
| assign index_lut[j] = j; | |
| end | |
| for (genvar level = 0; level < NUM_LEVELS; level++) begin | |
| if (level < NUM_LEVELS-1) begin | |
| for (genvar l = 0; l < 2**level; l++) begin | |
| assign sel_nodes[2**level-1+l] = sel_nodes[2**(level+1)-1+l*2] | sel_nodes[2**(level+1)-1+l*2+1]; | |
| assign index_nodes[2**level-1+l] = (sel_nodes[2**(level+1)-1+l*2] == 1'b1) ? | |
| index_nodes[2**(level+1)-1+l*2] : index_nodes[2**(level+1)-1+l*2+1]; | |
| end | |
| end | |
| if (level == NUM_LEVELS-1) begin | |
| for (genvar k = 0; k < 2**level; k++) begin | |
| if (k * 2 < WIDTH-1) begin | |
| assign sel_nodes[2**level-1+k] = in_tmp[k*2] | in_tmp[k*2+1]; | |
| assign index_nodes[2**level-1+k] = (in_tmp[k*2] == 1'b1) ? index_lut[k*2] : index_lut[k*2+1]; | |
| end | |
| if (k * 2 == WIDTH-1) begin | |
| assign sel_nodes[2**level-1+k] = in_tmp[k*2]; | |
| assign index_nodes[2**level-1+k] = index_lut[k*2]; | |
| end | |
| if (k * 2 > WIDTH-1) begin | |
| assign sel_nodes[2**level-1+k] = 1'b0; | |
| assign index_nodes[2**level-1+k] = '0; | |
| end | |
| end | |
| end | |
| end | |
| assign first_one_o = NUM_LEVELS > 0 ? index_nodes[0] : '0; | |
| assign no_ones_o = NUM_LEVELS > 0 ? ~sel_nodes[0] : '1; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module generic_LFSR_8bit | |
| #( | |
| parameter OH_WIDTH = 4, | |
| parameter BIN_WIDTH = $clog2(OH_WIDTH), | |
| parameter SEED = 8'b00000000 | |
| ) | |
| ( | |
| output logic [OH_WIDTH-1:0] data_OH_o, | |
| output logic [BIN_WIDTH-1:0] data_BIN_o, | |
| input logic enable_i, | |
| input logic clk, | |
| input logic rst_n | |
| ); | |
| logic [7:0] out; | |
| logic linear_feedback; | |
| logic [BIN_WIDTH-1:0] temp_ref_way; | |
| assign linear_feedback = !(out[7] ^ out[3] ^ out[2] ^ out[1]); | |
| assign data_BIN_o = temp_ref_way; | |
| always_ff @(posedge clk, negedge rst_n) | |
| begin | |
| if (rst_n == 1'b0) | |
| begin | |
| out <= SEED ; | |
| end | |
| else if (enable_i) | |
| begin | |
| out <= {out[6],out[5],out[4],out[3],out[2],out[1],out[0], linear_feedback}; | |
| end | |
| end | |
| generate | |
| if(OH_WIDTH == 2) | |
| assign temp_ref_way = out[1]; | |
| else | |
| assign temp_ref_way = out[BIN_WIDTH:1]; | |
| endgenerate | |
| always_comb | |
| begin | |
| data_OH_o = '0; | |
| data_OH_o[temp_ref_way] = 1'b1; | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module generic_fifo | |
| #( | |
| parameter int unsigned DATA_WIDTH = 32, | |
| parameter int unsigned DATA_DEPTH = 8 | |
| ) | |
| ( | |
| input logic clk, | |
| input logic rst_n, | |
| input logic [DATA_WIDTH-1:0] data_i, | |
| input logic valid_i, | |
| output logic grant_o, | |
| output logic [DATA_WIDTH-1:0] data_o, | |
| output logic valid_o, | |
| input logic grant_i, | |
| input logic test_mode_i | |
| ); | |
| localparam int unsigned ADDR_DEPTH = $clog2(DATA_DEPTH); | |
| enum logic [1:0] { EMPTY, FULL, MIDDLE } CS, NS; | |
| logic gate_clock; | |
| logic clk_gated; | |
| logic [ADDR_DEPTH-1:0] Pop_Pointer_CS, Pop_Pointer_NS; | |
| logic [ADDR_DEPTH-1:0] Push_Pointer_CS, Push_Pointer_NS; | |
| logic [DATA_WIDTH-1:0] FIFO_REGISTERS[DATA_DEPTH-1:0]; | |
| int unsigned i; | |
| initial begin : parameter_check | |
| integer param_err_flg; | |
| param_err_flg = 0; | |
| if (DATA_WIDTH < 1) begin | |
| param_err_flg = 1; | |
| $display("ERROR: %m :\n Invalid value (%d) for parameter DATA_WIDTH (legal range: greater than 1)", DATA_WIDTH ); | |
| end | |
| if (DATA_DEPTH < 1) begin | |
| param_err_flg = 1; | |
| $display("ERROR: %m :\n Invalid value (%d) for parameter DATA_DEPTH (legal range: greater than 1)", DATA_DEPTH ); | |
| end | |
| end | |
| cluster_clock_gating cg_cell | |
| ( | |
| .clk_i ( clk ), | |
| .en_i (~gate_clock ), | |
| .test_en_i ( test_mode_i ), | |
| .clk_o ( clk_gated ) | |
| ); | |
| always_ff @(posedge clk, negedge rst_n) | |
| begin | |
| if(rst_n == 1'b0) | |
| begin | |
| CS <= EMPTY; | |
| Pop_Pointer_CS <= {ADDR_DEPTH {1'b0}}; | |
| Push_Pointer_CS <= {ADDR_DEPTH {1'b0}}; | |
| end | |
| else | |
| begin | |
| CS <= NS; | |
| Pop_Pointer_CS <= Pop_Pointer_NS; | |
| Push_Pointer_CS <= Push_Pointer_NS; | |
| end | |
| end | |
| always_comb | |
| begin | |
| gate_clock = 1'b0; | |
| case(CS) | |
| EMPTY: | |
| begin | |
| grant_o = 1'b1; | |
| valid_o = 1'b0; | |
| case(valid_i) | |
| 1'b0 : | |
| begin | |
| NS = EMPTY; | |
| Push_Pointer_NS = Push_Pointer_CS; | |
| Pop_Pointer_NS = Pop_Pointer_CS; | |
| gate_clock = 1'b1; | |
| end | |
| 1'b1: | |
| begin | |
| NS = MIDDLE; | |
| Push_Pointer_NS = Push_Pointer_CS + 1'b1; | |
| Pop_Pointer_NS = Pop_Pointer_CS; | |
| end | |
| endcase | |
| end | |
| MIDDLE: | |
| begin | |
| grant_o = 1'b1; | |
| valid_o = 1'b1; | |
| case({valid_i,grant_i}) | |
| 2'b01: | |
| begin | |
| gate_clock = 1'b1; | |
| if((Pop_Pointer_CS == Push_Pointer_CS -1 ) || ((Pop_Pointer_CS == DATA_DEPTH-1) && (Push_Pointer_CS == 0) )) | |
| NS = EMPTY; | |
| else | |
| NS = MIDDLE; | |
| Push_Pointer_NS = Push_Pointer_CS; | |
| if(Pop_Pointer_CS == DATA_DEPTH-1) | |
| Pop_Pointer_NS = 0; | |
| else | |
| Pop_Pointer_NS = Pop_Pointer_CS + 1'b1; | |
| end | |
| 2'b00 : | |
| begin | |
| gate_clock = 1'b1; | |
| NS = MIDDLE; | |
| Push_Pointer_NS = Push_Pointer_CS; | |
| Pop_Pointer_NS = Pop_Pointer_CS; | |
| end | |
| 2'b11: | |
| begin | |
| NS = MIDDLE; | |
| if(Push_Pointer_CS == DATA_DEPTH-1) | |
| Push_Pointer_NS = 0; | |
| else | |
| Push_Pointer_NS = Push_Pointer_CS + 1'b1; | |
| if(Pop_Pointer_CS == DATA_DEPTH-1) | |
| Pop_Pointer_NS = 0; | |
| else | |
| Pop_Pointer_NS = Pop_Pointer_CS + 1'b1; | |
| end | |
| 2'b10: | |
| begin | |
| if(( Push_Pointer_CS == Pop_Pointer_CS - 1) || ( (Push_Pointer_CS == DATA_DEPTH-1) && (Pop_Pointer_CS == 0) )) | |
| NS = FULL; | |
| else | |
| NS = MIDDLE; | |
| if(Push_Pointer_CS == DATA_DEPTH - 1) | |
| Push_Pointer_NS = 0; | |
| else | |
| Push_Pointer_NS = Push_Pointer_CS + 1'b1; | |
| Pop_Pointer_NS = Pop_Pointer_CS; | |
| end | |
| endcase | |
| end | |
| FULL: | |
| begin | |
| grant_o = 1'b0; | |
| valid_o = 1'b1; | |
| gate_clock = 1'b1; | |
| case(grant_i) | |
| 1'b1: | |
| begin | |
| NS = MIDDLE; | |
| Push_Pointer_NS = Push_Pointer_CS; | |
| if(Pop_Pointer_CS == DATA_DEPTH-1) | |
| Pop_Pointer_NS = 0; | |
| else | |
| Pop_Pointer_NS = Pop_Pointer_CS + 1'b1; | |
| end | |
| 1'b0: | |
| begin | |
| NS = FULL; | |
| Push_Pointer_NS = Push_Pointer_CS; | |
| Pop_Pointer_NS = Pop_Pointer_CS; | |
| end | |
| endcase | |
| end | |
| default : | |
| begin | |
| gate_clock = 1'b1; | |
| grant_o = 1'b0; | |
| valid_o = 1'b0; | |
| NS = EMPTY; | |
| Pop_Pointer_NS = 0; | |
| Push_Pointer_NS = 0; | |
| end | |
| endcase | |
| end | |
| always_ff @(posedge clk_gated, negedge rst_n) | |
| begin | |
| if(rst_n == 1'b0) | |
| begin | |
| for (i=0; i< DATA_DEPTH; i++) | |
| FIFO_REGISTERS[i] <= {DATA_WIDTH {1'b0}}; | |
| end | |
| else | |
| begin | |
| if((grant_o == 1'b1) && (valid_i == 1'b1)) | |
| FIFO_REGISTERS[Push_Pointer_CS] <= data_i; | |
| end | |
| end | |
| assign data_o = FIFO_REGISTERS[Pop_Pointer_CS]; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module prioarbiter #( | |
| parameter int unsigned NUM_REQ = 13, | |
| parameter int unsigned LOCK_IN = 0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input logic en_i, | |
| input logic [NUM_REQ-1:0] req_i, | |
| output logic [NUM_REQ-1:0] ack_o, | |
| output logic vld_o, | |
| output logic [$clog2(NUM_REQ)-1:0] idx_o | |
| ); | |
| localparam SEL_WIDTH = $clog2(NUM_REQ); | |
| logic [SEL_WIDTH-1:0] arb_sel_lock_d, arb_sel_lock_q; | |
| logic lock_d, lock_q; | |
| logic [$clog2(NUM_REQ)-1:0] idx; | |
| assign vld_o = (|req_i) & en_i; | |
| assign idx_o = (lock_q) ? arb_sel_lock_q : idx; | |
| assign ack_o[0] = (req_i[0]) ? en_i : 1'b0; | |
| for (genvar i = 1; i < NUM_REQ; i++) begin : gen_arb_req_ports | |
| assign ack_o[i] = (req_i[i] & ~(|ack_o[i-1:0])) ? en_i : 1'b0; | |
| end | |
| onehot_to_bin #( | |
| .ONEHOT_WIDTH ( NUM_REQ ) | |
| ) i_onehot_to_bin ( | |
| .onehot ( ack_o ), | |
| .bin ( idx ) | |
| ); | |
| if (LOCK_IN) begin : gen_lock_in | |
| assign lock_d = (|req_i) & ~en_i; | |
| assign arb_sel_lock_d = idx_o; | |
| end else begin | |
| assign lock_d = '0; | |
| assign arb_sel_lock_d = '0; | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : p_regs | |
| if (!rst_ni) begin | |
| lock_q <= 1'b0; | |
| arb_sel_lock_q <= '0; | |
| end else begin | |
| if (flush_i) begin | |
| lock_q <= 1'b0; | |
| arb_sel_lock_q <= '0; | |
| end else begin | |
| lock_q <= lock_d; | |
| arb_sel_lock_q <= arb_sel_lock_d; | |
| end | |
| end | |
| end | |
| endmodule : prioarbiter | |
| `begin_keywords "1800-2023" | |
| module pulp_sync | |
| #( | |
| parameter STAGES = 2 | |
| ) | |
| ( | |
| input logic clk_i, | |
| input logic rstn_i, | |
| input logic serial_i, | |
| output logic serial_o | |
| ); | |
| logic [STAGES-1:0] r_reg; | |
| always_ff @(posedge clk_i, negedge rstn_i) | |
| begin | |
| if(!rstn_i) | |
| r_reg <= 'h0; | |
| else | |
| r_reg <= {r_reg[STAGES-2:0], serial_i}; | |
| end | |
| assign serial_o = r_reg[STAGES-1]; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module pulp_sync_wedge #( | |
| parameter int unsigned STAGES = 2 | |
| ) ( | |
| input logic clk_i, | |
| input logic rstn_i, | |
| input logic en_i, | |
| input logic serial_i, | |
| output logic r_edge_o, | |
| output logic f_edge_o, | |
| output logic serial_o | |
| ); | |
| logic clk; | |
| logic serial, serial_q; | |
| assign serial_o = serial_q; | |
| assign f_edge_o = ~serial & serial_q; | |
| assign r_edge_o = serial & ~serial_q; | |
| pulp_sync #( | |
| .STAGES(STAGES) | |
| ) i_pulp_sync ( | |
| .clk_i, | |
| .rstn_i, | |
| .serial_i, | |
| .serial_o ( serial ) | |
| ); | |
| pulp_clock_gating i_pulp_clock_gating ( | |
| .clk_i, | |
| .en_i, | |
| .test_en_i ( 1'b0 ), | |
| .clk_o ( clk ) | |
| ); | |
| always_ff @(posedge clk, negedge rstn_i) begin | |
| if (!rstn_i) begin | |
| serial_q <= 1'b0; | |
| end else begin | |
| serial_q <= serial; | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module rrarbiter #( | |
| parameter int unsigned NUM_REQ = 64, | |
| parameter bit LOCK_IN = 1'b0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input logic en_i, | |
| input logic [NUM_REQ-1:0] req_i, | |
| output logic [NUM_REQ-1:0] ack_o, | |
| output logic vld_o, | |
| output logic [$clog2(NUM_REQ)-1:0] idx_o | |
| ); | |
| logic req; | |
| assign vld_o = (|req_i) & en_i; | |
| rr_arb_tree #( | |
| .NumIn ( NUM_REQ ), | |
| .DataWidth ( 1 ), | |
| .LockIn ( LOCK_IN )) | |
| i_rr_arb_tree ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( flush_i ), | |
| .rr_i ( '0 ), | |
| .req_i ( req_i ), | |
| .gnt_o ( ack_o ), | |
| .data_i ( '0 ), | |
| .gnt_i ( en_i & req ), | |
| .req_o ( req ), | |
| .data_o ( ), | |
| .idx_o ( idx_o ) | |
| ); | |
| endmodule : rrarbiter | |
| `begin_keywords "1800-2023" | |
| module clock_divider | |
| #( | |
| parameter DIV_INIT = 0, | |
| parameter BYPASS_INIT = 1 | |
| ) | |
| ( | |
| input logic clk_i, | |
| input logic rstn_i, | |
| input logic test_mode_i, | |
| input logic clk_gate_async_i, | |
| input logic [7:0] clk_div_data_i, | |
| input logic clk_div_valid_i, | |
| output logic clk_div_ack_o, | |
| output logic clk_o | |
| ); | |
| enum logic [1:0] {IDLE, STOP, WAIT, RELEASE} state, state_next; | |
| logic s_clk_out; | |
| logic s_clock_enable; | |
| logic s_clock_enable_gate; | |
| logic s_clk_div_valid; | |
| logic [7:0] reg_clk_div; | |
| logic s_clk_div_valid_sync; | |
| logic s_rstn_sync; | |
| logic [1:0] reg_ext_gate_sync; | |
| assign s_clock_enable_gate = s_clock_enable & reg_ext_gate_sync; | |
| rstgen i_rst_gen | |
| ( | |
| .clk_i(clk_i), | |
| .rst_ni(rstn_i), | |
| .test_mode_i(test_mode_i), | |
| .rst_no(s_rstn_sync), | |
| .init_no() | |
| ); | |
| pulp_sync_wedge i_edge_prop | |
| ( | |
| .clk_i(clk_i), | |
| .rstn_i(s_rstn_sync), | |
| .en_i(1'b1), | |
| .serial_i(clk_div_valid_i), | |
| .serial_o(clk_div_ack_o), | |
| .r_edge_o(s_clk_div_valid_sync), | |
| .f_edge_o() | |
| ); | |
| clock_divider_counter | |
| #( | |
| .BYPASS_INIT(BYPASS_INIT), | |
| .DIV_INIT(DIV_INIT) | |
| ) | |
| i_clkdiv_cnt | |
| ( | |
| .clk(clk_i), | |
| .rstn(s_rstn_sync), | |
| .test_mode(test_mode_i), | |
| .clk_div(reg_clk_div), | |
| .clk_div_valid(s_clk_div_valid), | |
| .clk_out(s_clk_out) | |
| ); | |
| pulp_clock_gating i_clk_gate | |
| ( | |
| .clk_i(s_clk_out), | |
| .en_i(s_clock_enable_gate), | |
| .test_en_i(test_mode_i), | |
| .clk_o(clk_o) | |
| ); | |
| always_comb | |
| begin | |
| case(state) | |
| IDLE: | |
| begin | |
| s_clock_enable = 1'b1; | |
| s_clk_div_valid = 1'b0; | |
| if (s_clk_div_valid_sync) | |
| state_next = STOP; | |
| else | |
| state_next = IDLE; | |
| end | |
| STOP: | |
| begin | |
| s_clock_enable = 1'b0; | |
| s_clk_div_valid = 1'b1; | |
| state_next = WAIT; | |
| end | |
| WAIT: | |
| begin | |
| s_clock_enable = 1'b0; | |
| s_clk_div_valid = 1'b0; | |
| state_next = RELEASE; | |
| end | |
| RELEASE: | |
| begin | |
| s_clock_enable = 1'b0; | |
| s_clk_div_valid = 1'b0; | |
| state_next = IDLE; | |
| end | |
| endcase | |
| end | |
| always_ff @(posedge clk_i or negedge s_rstn_sync) | |
| begin | |
| if (!s_rstn_sync) | |
| state <= IDLE; | |
| else | |
| state <= state_next; | |
| end | |
| always_ff @(posedge clk_i or negedge s_rstn_sync) | |
| begin | |
| if (!s_rstn_sync) | |
| reg_clk_div <= '0; | |
| else if (s_clk_div_valid_sync) | |
| reg_clk_div <= clk_div_data_i; | |
| end | |
| always_ff @(posedge clk_i or negedge s_rstn_sync) | |
| begin | |
| if (!s_rstn_sync) | |
| reg_ext_gate_sync <= 2'b00; | |
| else | |
| reg_ext_gate_sync <= {clk_gate_async_i, reg_ext_gate_sync[1]}; | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module fifo_v2 #( | |
| parameter bit FALL_THROUGH = 1'b0, | |
| parameter int unsigned DATA_WIDTH = 32, | |
| parameter int unsigned DEPTH = 8, | |
| parameter int unsigned ALM_EMPTY_TH = 1, | |
| parameter int unsigned ALM_FULL_TH = 1, | |
| parameter type dtype = logic [DATA_WIDTH-1:0], | |
| parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input logic testmode_i, | |
| output logic full_o, | |
| output logic empty_o, | |
| output logic alm_full_o, | |
| output logic alm_empty_o, | |
| input dtype data_i, | |
| input logic push_i, | |
| output dtype data_o, | |
| input logic pop_i | |
| ); | |
| logic [ADDR_DEPTH-1:0] usage; | |
| if (DEPTH == 0) begin | |
| assign alm_full_o = 1'b0; | |
| assign alm_empty_o = 1'b0; | |
| end else begin | |
| assign alm_full_o = (usage >= ALM_FULL_TH[ADDR_DEPTH-1:0]); | |
| assign alm_empty_o = (usage <= ALM_EMPTY_TH[ADDR_DEPTH-1:0]); | |
| end | |
| fifo_v3 #( | |
| .FALL_THROUGH ( FALL_THROUGH ), | |
| .DATA_WIDTH ( DATA_WIDTH ), | |
| .DEPTH ( DEPTH ), | |
| .dtype ( dtype ) | |
| ) i_fifo_v3 ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i, | |
| .testmode_i, | |
| .full_o, | |
| .empty_o, | |
| .usage_o (usage), | |
| .data_i, | |
| .push_i, | |
| .data_o, | |
| .pop_i | |
| ); | |
| initial begin | |
| assert (ALM_FULL_TH <= DEPTH) else $error("ALM_FULL_TH can't be larger than the DEPTH."); | |
| assert (ALM_EMPTY_TH <= DEPTH) else $error("ALM_EMPTY_TH can't be larger than the DEPTH."); | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| /*verilator lint_off DECLFILENAME*/ | |
| module fifo #( | |
| parameter bit FALL_THROUGH = 1'b0, | |
| parameter int unsigned DATA_WIDTH = 32, | |
| parameter int unsigned DEPTH = 8, | |
| parameter int unsigned THRESHOLD = 1, | |
| parameter type dtype = logic [DATA_WIDTH-1:0] | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic flush_i, | |
| input logic testmode_i, | |
| output logic full_o, | |
| output logic empty_o, | |
| output logic threshold_o, | |
| input dtype data_i, | |
| input logic push_i, | |
| output dtype data_o, | |
| input logic pop_i | |
| ); | |
| fifo_v2 #( | |
| .FALL_THROUGH ( FALL_THROUGH ), | |
| .DATA_WIDTH ( DATA_WIDTH ), | |
| .DEPTH ( DEPTH ), | |
| .ALM_FULL_TH ( THRESHOLD ), | |
| .dtype ( dtype ) | |
| ) impl ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( flush_i ), | |
| .testmode_i ( testmode_i ), | |
| .full_o ( full_o ), | |
| .empty_o ( empty_o ), | |
| .alm_full_o ( threshold_o ), | |
| .alm_empty_o ( ), | |
| .data_i ( data_i ), | |
| .push_i ( push_i ), | |
| .data_o ( data_o ), | |
| .pop_i ( pop_i ) | |
| ); | |
| endmodule | |
| /*verilator lint_on DECLFILENAME*/ | |
| `begin_keywords "1800-2023" | |
| module edge_propagator_ack ( | |
| input logic clk_tx_i, | |
| input logic rstn_tx_i, | |
| input logic edge_i, | |
| output logic ack_tx_o, | |
| input logic clk_rx_i, | |
| input logic rstn_rx_i, | |
| output logic edge_o | |
| ); | |
| logic [1:0] sync_a; | |
| logic sync_b; | |
| logic r_input_reg; | |
| logic s_input_reg_next; | |
| assign ack_tx_o = sync_a[0]; | |
| assign s_input_reg_next = edge_i | (r_input_reg & ~sync_a[0]); | |
| always @(negedge rstn_tx_i or posedge clk_tx_i) begin | |
| if (~rstn_tx_i) begin | |
| r_input_reg <= 1'b0; | |
| sync_a <= 2'b00; | |
| end else begin | |
| r_input_reg <= s_input_reg_next; | |
| sync_a <= {sync_b,sync_a[1]}; | |
| end | |
| end | |
| pulp_sync_wedge u_sync_clkb ( | |
| .clk_i ( clk_rx_i ), | |
| .rstn_i ( rstn_rx_i ), | |
| .en_i ( 1'b1 ), | |
| .serial_i ( r_input_reg ), | |
| .r_edge_o ( edge_o ), | |
| .f_edge_o ( ), | |
| .serial_o ( sync_b ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module edge_propagator ( | |
| input logic clk_tx_i, | |
| input logic rstn_tx_i, | |
| input logic edge_i, | |
| input logic clk_rx_i, | |
| input logic rstn_rx_i, | |
| output logic edge_o | |
| ); | |
| edge_propagator_ack i_edge_propagator_ack ( | |
| .clk_tx_i, | |
| .rstn_tx_i, | |
| .edge_i, | |
| .ack_tx_o ( ), | |
| .clk_rx_i, | |
| .rstn_rx_i, | |
| .edge_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module edge_propagator_rx ( | |
| input logic clk_i, | |
| input logic rstn_i, | |
| input logic valid_i, | |
| output logic ack_o, | |
| output logic valid_o | |
| ); | |
| pulp_sync_wedge i_sync_clkb ( | |
| .clk_i ( clk_i ), | |
| .rstn_i ( rstn_i ), | |
| .en_i ( 1'b1 ), | |
| .serial_i ( valid_i ), | |
| .r_edge_o ( valid_o ), | |
| .f_edge_o ( ), | |
| .serial_o ( ack_o ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| package axi_pkg; | |
| parameter int unsigned BurstWidth = 32'd2; | |
| parameter int unsigned RespWidth = 32'd2; | |
| parameter int unsigned CacheWidth = 32'd4; | |
| parameter int unsigned ProtWidth = 32'd3; | |
| parameter int unsigned QosWidth = 32'd4; | |
| parameter int unsigned RegionWidth = 32'd4; | |
| parameter int unsigned LenWidth = 32'd8; | |
| parameter int unsigned SizeWidth = 32'd3; | |
| parameter int unsigned LockWidth = 32'd1; | |
| parameter int unsigned AtopWidth = 32'd6; | |
| parameter int unsigned NsaidWidth = 32'd4; | |
| typedef logic [1:0] burst_t; | |
| typedef logic [1:0] resp_t; | |
| typedef logic [3:0] cache_t; | |
| typedef logic [2:0] prot_t; | |
| typedef logic [3:0] qos_t; | |
| typedef logic [3:0] region_t; | |
| typedef logic [7:0] len_t; | |
| typedef logic [2:0] size_t; | |
| typedef logic [5:0] atop_t; | |
| typedef logic [3:0] nsaid_t; | |
| localparam BURST_FIXED = 2'b00; | |
| localparam BURST_INCR = 2'b01; | |
| localparam BURST_WRAP = 2'b10; | |
| localparam RESP_OKAY = 2'b00; | |
| localparam RESP_EXOKAY = 2'b01; | |
| localparam RESP_SLVERR = 2'b10; | |
| localparam RESP_DECERR = 2'b11; | |
| localparam CACHE_BUFFERABLE = 4'b0001; | |
| localparam CACHE_MODIFIABLE = 4'b0010; | |
| localparam CACHE_RD_ALLOC = 4'b0100; | |
| localparam CACHE_WR_ALLOC = 4'b1000; | |
| function automatic shortint unsigned num_bytes(size_t size); | |
| return shortint'(1 << size); | |
| endfunction | |
| typedef logic [127:0] largest_addr_t; | |
| function automatic largest_addr_t aligned_addr(largest_addr_t addr, size_t size); | |
| return (addr >> size) << size; | |
| endfunction | |
| function automatic largest_addr_t wrap_boundary (largest_addr_t addr, size_t size, len_t len); | |
| largest_addr_t wrap_addr; | |
| unique case (len) | |
| len_t'(4'b1 ) : wrap_addr = (addr >> (unsigned'(size) + 1)) << (unsigned'(size) + 1); | |
| len_t'(4'b11 ) : wrap_addr = (addr >> (unsigned'(size) + 2)) << (unsigned'(size) + 2); | |
| len_t'(4'b111 ) : wrap_addr = (addr >> (unsigned'(size) + 3)) << (unsigned'(size) + 3); | |
| len_t'(4'b1111) : wrap_addr = (addr >> (unsigned'(size) + 4)) << (unsigned'(size) + 4); | |
| default : wrap_addr = '0; | |
| endcase | |
| return wrap_addr; | |
| endfunction | |
| function automatic largest_addr_t | |
| beat_addr(largest_addr_t addr, size_t size, len_t len, burst_t burst, shortint unsigned i_beat); | |
| largest_addr_t ret_addr = addr; | |
| largest_addr_t wrp_bond = '0; | |
| if (burst == BURST_WRAP) begin | |
| wrp_bond = wrap_boundary(addr, size, len); | |
| end | |
| if (i_beat != 0 && burst != BURST_FIXED) begin | |
| ret_addr = aligned_addr(addr, size) + i_beat * num_bytes(size); | |
| if (burst == BURST_WRAP && ret_addr >= wrp_bond + (num_bytes(size) * (largest_addr_t'(len) + 1))) begin | |
| ret_addr = ret_addr - (num_bytes(size) * (largest_addr_t'(len) + 1)); | |
| end | |
| end | |
| return ret_addr; | |
| endfunction | |
| function automatic shortint unsigned | |
| beat_lower_byte(largest_addr_t addr, size_t size, len_t len, burst_t burst, | |
| shortint unsigned strobe_width, shortint unsigned i_beat); | |
| largest_addr_t _addr = beat_addr(addr, size, len, burst, i_beat); | |
| return shortint'(($bits(_addr) + $bits(strobe_width))'(_addr) - (_addr / largest_addr_t'(strobe_width)) * strobe_width); | |
| endfunction | |
| function automatic shortint unsigned | |
| beat_upper_byte(largest_addr_t addr, size_t size, len_t len, burst_t burst, | |
| shortint unsigned strobe_width, shortint unsigned i_beat); | |
| typedef shortint unsigned SU; | |
| if (i_beat == 0) begin | |
| return SU'(aligned_addr(addr, size) + (largest_addr_t'(num_bytes(size)) - 1) - (addr / largest_addr_t'(strobe_width)) * strobe_width); | |
| end else begin | |
| return beat_lower_byte(addr, size, len, burst, strobe_width, i_beat) + num_bytes(size) - 1; | |
| end | |
| endfunction | |
| function automatic logic bufferable(cache_t cache); | |
| return |(cache & CACHE_BUFFERABLE); | |
| endfunction | |
| function automatic logic modifiable(cache_t cache); | |
| return |(cache & CACHE_MODIFIABLE); | |
| endfunction | |
| typedef enum logic [3:0] { | |
| DEVICE_NONBUFFERABLE, | |
| DEVICE_BUFFERABLE, | |
| NORMAL_NONCACHEABLE_NONBUFFERABLE, | |
| NORMAL_NONCACHEABLE_BUFFERABLE, | |
| WTHRU_NOALLOCATE, | |
| WTHRU_RALLOCATE, | |
| WTHRU_WALLOCATE, | |
| WTHRU_RWALLOCATE, | |
| WBACK_NOALLOCATE, | |
| WBACK_RALLOCATE, | |
| WBACK_WALLOCATE, | |
| WBACK_RWALLOCATE | |
| } mem_type_t; | |
| function automatic logic [3:0] get_arcache(mem_type_t mtype); | |
| unique case (mtype) | |
| DEVICE_NONBUFFERABLE : return 4'b0000; | |
| DEVICE_BUFFERABLE : return 4'b0001; | |
| NORMAL_NONCACHEABLE_NONBUFFERABLE : return 4'b0010; | |
| NORMAL_NONCACHEABLE_BUFFERABLE : return 4'b0011; | |
| WTHRU_NOALLOCATE : return 4'b1010; | |
| WTHRU_RALLOCATE : return 4'b1110; | |
| WTHRU_WALLOCATE : return 4'b1010; | |
| WTHRU_RWALLOCATE : return 4'b1110; | |
| WBACK_NOALLOCATE : return 4'b1011; | |
| WBACK_RALLOCATE : return 4'b1111; | |
| WBACK_WALLOCATE : return 4'b1011; | |
| WBACK_RWALLOCATE : return 4'b1111; | |
| default : return 4'bxxxx; | |
| endcase | |
| endfunction | |
| function automatic logic [3:0] get_awcache(mem_type_t mtype); | |
| unique case (mtype) | |
| DEVICE_NONBUFFERABLE : return 4'b0000; | |
| DEVICE_BUFFERABLE : return 4'b0001; | |
| NORMAL_NONCACHEABLE_NONBUFFERABLE : return 4'b0010; | |
| NORMAL_NONCACHEABLE_BUFFERABLE : return 4'b0011; | |
| WTHRU_NOALLOCATE : return 4'b0110; | |
| WTHRU_RALLOCATE : return 4'b0110; | |
| WTHRU_WALLOCATE : return 4'b1110; | |
| WTHRU_RWALLOCATE : return 4'b1110; | |
| WBACK_NOALLOCATE : return 4'b0111; | |
| WBACK_RALLOCATE : return 4'b0111; | |
| WBACK_WALLOCATE : return 4'b1111; | |
| WBACK_RWALLOCATE : return 4'b1111; | |
| default : return 4'bxxxx; | |
| endcase | |
| endfunction | |
| function automatic resp_t resp_precedence(resp_t resp_a, resp_t resp_b); | |
| unique case (resp_a) | |
| RESP_OKAY: begin | |
| if (resp_b == RESP_EXOKAY) begin | |
| return resp_a; | |
| end else begin | |
| return resp_b; | |
| end | |
| end | |
| RESP_EXOKAY: begin | |
| return resp_b; | |
| end | |
| RESP_SLVERR: begin | |
| if (resp_b == RESP_DECERR) begin | |
| return resp_b; | |
| end else begin | |
| return resp_a; | |
| end | |
| end | |
| RESP_DECERR: begin | |
| return resp_a; | |
| end | |
| endcase | |
| endfunction | |
| function automatic int unsigned aw_width(int unsigned addr_width, int unsigned id_width, | |
| int unsigned user_width ); | |
| return (id_width + addr_width + LenWidth + SizeWidth + BurstWidth + LockWidth + CacheWidth + | |
| ProtWidth + QosWidth + RegionWidth + AtopWidth + user_width ); | |
| endfunction | |
| function automatic int unsigned w_width(int unsigned data_width, int unsigned user_width ); | |
| return (data_width + data_width / 32'd8 + 32'd1 + user_width); | |
| endfunction | |
| function automatic int unsigned b_width(int unsigned id_width, int unsigned user_width ); | |
| return (id_width + RespWidth + user_width); | |
| endfunction | |
| function automatic int unsigned ar_width(int unsigned addr_width, int unsigned id_width, | |
| int unsigned user_width ); | |
| return (id_width + addr_width + LenWidth + SizeWidth + BurstWidth + LockWidth + CacheWidth + | |
| ProtWidth + QosWidth + RegionWidth + user_width ); | |
| endfunction | |
| function automatic int unsigned r_width(int unsigned data_width, int unsigned id_width, | |
| int unsigned user_width ); | |
| return (id_width + data_width + RespWidth + 32'd1 + user_width); | |
| endfunction | |
| function automatic int unsigned req_width(int unsigned addr_width, int unsigned data_width, | |
| int unsigned id_width, int unsigned aw_user_width, | |
| int unsigned ar_user_width, int unsigned w_user_width ); | |
| return (aw_width(addr_width, id_width, aw_user_width) + 32'd1 + | |
| w_width(data_width, w_user_width) + 32'd1 + | |
| ar_width(addr_width, id_width, ar_user_width) + 32'd1 + 32'd1 + 32'd1 ); | |
| endfunction | |
| function automatic int unsigned rsp_width(int unsigned data_width, int unsigned id_width, | |
| int unsigned r_user_width, int unsigned b_user_width ); | |
| return (r_width(data_width, id_width, r_user_width) + 32'd1 + | |
| b_width(id_width, b_user_width) + 32'd1 + 32'd1 + 32'd1 + 32'd1); | |
| endfunction | |
| localparam ATOP_ATOMICSWAP = 6'b110000; | |
| localparam ATOP_ATOMICCMP = 6'b110001; | |
| localparam ATOP_NONE = 2'b00; | |
| localparam ATOP_ATOMICSTORE = 2'b01; | |
| localparam ATOP_ATOMICLOAD = 2'b10; | |
| localparam ATOP_LITTLE_END = 1'b0; | |
| localparam ATOP_BIG_END = 1'b1; | |
| localparam ATOP_ADD = 3'b000; | |
| localparam ATOP_CLR = 3'b001; | |
| localparam ATOP_EOR = 3'b010; | |
| localparam ATOP_SET = 3'b011; | |
| localparam ATOP_SMAX = 3'b100; | |
| localparam ATOP_SMIN = 3'b101; | |
| localparam ATOP_UMAX = 3'b110; | |
| localparam ATOP_UMIN = 3'b111; | |
| localparam ATOP_R_RESP = 32'd5; | |
| localparam bit [9:0] DemuxAw = (1 << 9); | |
| localparam bit [9:0] DemuxW = (1 << 8); | |
| localparam bit [9:0] DemuxB = (1 << 7); | |
| localparam bit [9:0] DemuxAr = (1 << 6); | |
| localparam bit [9:0] DemuxR = (1 << 5); | |
| localparam bit [9:0] MuxAw = (1 << 4); | |
| localparam bit [9:0] MuxW = (1 << 3); | |
| localparam bit [9:0] MuxB = (1 << 2); | |
| localparam bit [9:0] MuxAr = (1 << 1); | |
| localparam bit [9:0] MuxR = (1 << 0); | |
| typedef enum bit [9:0] { | |
| NO_LATENCY = 10'b000_00_000_00, | |
| CUT_SLV_AX = DemuxAw | DemuxAr, | |
| CUT_MST_AX = MuxAw | MuxAr, | |
| CUT_ALL_AX = DemuxAw | DemuxAr | MuxAw | MuxAr, | |
| CUT_SLV_PORTS = DemuxAw | DemuxW | DemuxB | DemuxAr | DemuxR, | |
| CUT_MST_PORTS = MuxAw | MuxW | MuxB | MuxAr | MuxR, | |
| CUT_ALL_PORTS = 10'b111_11_111_11 | |
| } xbar_latency_e; | |
| typedef struct packed { | |
| int unsigned NoSlvPorts; | |
| int unsigned NoMstPorts; | |
| int unsigned MaxMstTrans; | |
| int unsigned MaxSlvTrans; | |
| bit FallThrough; | |
| bit [9:0] LatencyMode; | |
| int unsigned PipelineStages; | |
| int unsigned AxiIdWidthSlvPorts; | |
| int unsigned AxiIdUsedSlvPorts; | |
| bit UniqueIds; | |
| int unsigned AxiAddrWidth; | |
| int unsigned AxiDataWidth; | |
| int unsigned NoAddrRules; | |
| } xbar_cfg_t; | |
| typedef struct packed { | |
| int unsigned idx; | |
| logic [63:0] start_addr; | |
| logic [63:0] end_addr; | |
| } xbar_rule_64_t; | |
| typedef struct packed { | |
| int unsigned idx; | |
| logic [31:0] start_addr; | |
| logic [31:0] end_addr; | |
| } xbar_rule_32_t; | |
| function automatic integer unsigned iomsb (input integer unsigned width); | |
| return (width != 32'd0) ? unsigned'(width-1) : 32'd0; | |
| endfunction | |
| endpackage | |
| `begin_keywords "1800-2023" | |
| module axi_demux_id_counters #( | |
| parameter int unsigned AxiIdBits = 2, | |
| parameter int unsigned CounterWidth = 4, | |
| parameter type mst_port_select_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic [AxiIdBits-1:0] lookup_axi_id_i, | |
| output mst_port_select_t lookup_mst_select_o, | |
| output logic lookup_mst_select_occupied_o, | |
| output logic full_o, | |
| input logic [AxiIdBits-1:0] push_axi_id_i, | |
| input mst_port_select_t push_mst_select_i, | |
| input logic push_i, | |
| input logic [AxiIdBits-1:0] inject_axi_id_i, | |
| input logic inject_i, | |
| input logic [AxiIdBits-1:0] pop_axi_id_i, | |
| input logic pop_i, | |
| output logic any_outstanding_trx_o | |
| ); | |
| localparam int unsigned NoCounters = 2**AxiIdBits; | |
| typedef logic [CounterWidth-1:0] cnt_t; | |
| mst_port_select_t [NoCounters-1:0] mst_select_q; | |
| logic [NoCounters-1:0] push_en, inject_en, pop_en, occupied, cnt_full; | |
| assign lookup_mst_select_o = mst_select_q[lookup_axi_id_i]; | |
| assign lookup_mst_select_occupied_o = occupied[lookup_axi_id_i]; | |
| assign push_en = (push_i) ? (1 << push_axi_id_i) : '0; | |
| assign inject_en = (inject_i) ? (1 << inject_axi_id_i) : '0; | |
| assign pop_en = (pop_i) ? (1 << pop_axi_id_i) : '0; | |
| assign full_o = |cnt_full; | |
| assign any_outstanding_trx_o = |occupied; | |
| for (genvar i = 0; i < NoCounters; i++) begin : gen_counters | |
| logic cnt_en, cnt_down, overflow; | |
| cnt_t cnt_delta, in_flight; | |
| always_comb begin | |
| unique case ({push_en[i], inject_en[i], pop_en[i]}) | |
| 3'b001 : begin | |
| cnt_en = 1'b1; | |
| cnt_down = 1'b1; | |
| cnt_delta = cnt_t'(1); | |
| end | |
| 3'b010 : begin | |
| cnt_en = 1'b1; | |
| cnt_down = 1'b0; | |
| cnt_delta = cnt_t'(1); | |
| end | |
| 3'b100 : begin | |
| cnt_en = 1'b1; | |
| cnt_down = 1'b0; | |
| cnt_delta = cnt_t'(1); | |
| end | |
| 3'b110 : begin | |
| cnt_en = 1'b1; | |
| cnt_down = 1'b0; | |
| cnt_delta = cnt_t'(2); | |
| end | |
| 3'b111 : begin | |
| cnt_en = 1'b1; | |
| cnt_down = 1'b0; | |
| cnt_delta = cnt_t'(1); | |
| end | |
| default : begin | |
| cnt_en = 1'b0; | |
| cnt_down = 1'b0; | |
| cnt_delta = cnt_t'(0); | |
| end | |
| endcase | |
| end | |
| delta_counter #( | |
| .WIDTH ( CounterWidth ), | |
| .STICKY_OVERFLOW ( 1'b0 ) | |
| ) i_in_flight_cnt ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .clear_i ( 1'b0 ), | |
| .en_i ( cnt_en ), | |
| .load_i ( 1'b0 ), | |
| .down_i ( cnt_down ), | |
| .delta_i ( cnt_delta ), | |
| .d_i ( '0 ), | |
| .q_o ( in_flight ), | |
| .overflow_o ( overflow ) | |
| ); | |
| assign occupied[i] = |in_flight; | |
| assign cnt_full[i] = overflow | (&in_flight); | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| mst_select_q[i] <= ('0); | |
| end else begin | |
| if (push_en[i]) begin | |
| mst_select_q[i] <= (push_mst_select_i); | |
| end | |
| end | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| interface AXI_BUS #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0 | |
| ); | |
| localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_STRB_WIDTH-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| id_t aw_id; | |
| addr_t aw_addr; | |
| axi_pkg::len_t aw_len; | |
| axi_pkg::size_t aw_size; | |
| axi_pkg::burst_t aw_burst; | |
| logic aw_lock; | |
| axi_pkg::cache_t aw_cache; | |
| axi_pkg::prot_t aw_prot; | |
| axi_pkg::qos_t aw_qos; | |
| axi_pkg::region_t aw_region; | |
| axi_pkg::atop_t aw_atop; | |
| user_t aw_user; | |
| logic aw_valid; | |
| logic aw_ready; | |
| data_t w_data; | |
| strb_t w_strb; | |
| logic w_last; | |
| user_t w_user; | |
| logic w_valid; | |
| logic w_ready; | |
| id_t b_id; | |
| axi_pkg::resp_t b_resp; | |
| user_t b_user; | |
| logic b_valid; | |
| logic b_ready; | |
| id_t ar_id; | |
| addr_t ar_addr; | |
| axi_pkg::len_t ar_len; | |
| axi_pkg::size_t ar_size; | |
| axi_pkg::burst_t ar_burst; | |
| logic ar_lock; | |
| axi_pkg::cache_t ar_cache; | |
| axi_pkg::prot_t ar_prot; | |
| axi_pkg::qos_t ar_qos; | |
| axi_pkg::region_t ar_region; | |
| user_t ar_user; | |
| logic ar_valid; | |
| logic ar_ready; | |
| id_t r_id; | |
| data_t r_data; | |
| axi_pkg::resp_t r_resp; | |
| logic r_last; | |
| user_t r_user; | |
| logic r_valid; | |
| logic r_ready; | |
| modport Master ( | |
| output aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, input aw_ready, | |
| output w_data, w_strb, w_last, w_user, w_valid, input w_ready, | |
| input b_id, b_resp, b_user, b_valid, output b_ready, | |
| output ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, input ar_ready, | |
| input r_id, r_data, r_resp, r_last, r_user, r_valid, output r_ready | |
| ); | |
| modport Slave ( | |
| input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, output aw_ready, | |
| input w_data, w_strb, w_last, w_user, w_valid, output w_ready, | |
| output b_id, b_resp, b_user, b_valid, input b_ready, | |
| input ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, output ar_ready, | |
| output r_id, r_data, r_resp, r_last, r_user, r_valid, input r_ready | |
| ); | |
| modport Monitor ( | |
| input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_ready, | |
| w_data, w_strb, w_last, w_user, w_valid, w_ready, | |
| b_id, b_resp, b_user, b_valid, b_ready, | |
| ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_ready, | |
| r_id, r_data, r_resp, r_last, r_user, r_valid, r_ready | |
| ); | |
| endinterface | |
| interface AXI_BUS_DV #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0 | |
| )( | |
| input logic clk_i | |
| ); | |
| localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_STRB_WIDTH-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| id_t aw_id; | |
| addr_t aw_addr; | |
| axi_pkg::len_t aw_len; | |
| axi_pkg::size_t aw_size; | |
| axi_pkg::burst_t aw_burst; | |
| logic aw_lock; | |
| axi_pkg::cache_t aw_cache; | |
| axi_pkg::prot_t aw_prot; | |
| axi_pkg::qos_t aw_qos; | |
| axi_pkg::region_t aw_region; | |
| axi_pkg::atop_t aw_atop; | |
| user_t aw_user; | |
| logic aw_valid; | |
| logic aw_ready; | |
| data_t w_data; | |
| strb_t w_strb; | |
| logic w_last; | |
| user_t w_user; | |
| logic w_valid; | |
| logic w_ready; | |
| id_t b_id; | |
| axi_pkg::resp_t b_resp; | |
| user_t b_user; | |
| logic b_valid; | |
| logic b_ready; | |
| id_t ar_id; | |
| addr_t ar_addr; | |
| axi_pkg::len_t ar_len; | |
| axi_pkg::size_t ar_size; | |
| axi_pkg::burst_t ar_burst; | |
| logic ar_lock; | |
| axi_pkg::cache_t ar_cache; | |
| axi_pkg::prot_t ar_prot; | |
| axi_pkg::qos_t ar_qos; | |
| axi_pkg::region_t ar_region; | |
| user_t ar_user; | |
| logic ar_valid; | |
| logic ar_ready; | |
| id_t r_id; | |
| data_t r_data; | |
| axi_pkg::resp_t r_resp; | |
| logic r_last; | |
| user_t r_user; | |
| logic r_valid; | |
| logic r_ready; | |
| modport Master ( | |
| output aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, input aw_ready, | |
| output w_data, w_strb, w_last, w_user, w_valid, input w_ready, | |
| input b_id, b_resp, b_user, b_valid, output b_ready, | |
| output ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, input ar_ready, | |
| input r_id, r_data, r_resp, r_last, r_user, r_valid, output r_ready | |
| ); | |
| modport Slave ( | |
| input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, output aw_ready, | |
| input w_data, w_strb, w_last, w_user, w_valid, output w_ready, | |
| output b_id, b_resp, b_user, b_valid, input b_ready, | |
| input ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, output ar_ready, | |
| output r_id, r_data, r_resp, r_last, r_user, r_valid, input r_ready | |
| ); | |
| modport Monitor ( | |
| input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_ready, | |
| w_data, w_strb, w_last, w_user, w_valid, w_ready, | |
| b_id, b_resp, b_user, b_valid, b_ready, | |
| ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_ready, | |
| r_id, r_data, r_resp, r_last, r_user, r_valid, r_ready | |
| ); | |
| endinterface | |
| interface AXI_BUS_ASYNC | |
| #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0, | |
| parameter int unsigned BUFFER_WIDTH = 0 | |
| ); | |
| localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_STRB_WIDTH-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| typedef logic [BUFFER_WIDTH-1:0] buffer_t; | |
| id_t aw_id; | |
| addr_t aw_addr; | |
| axi_pkg::len_t aw_len; | |
| axi_pkg::size_t aw_size; | |
| axi_pkg::burst_t aw_burst; | |
| logic aw_lock; | |
| axi_pkg::cache_t aw_cache; | |
| axi_pkg::prot_t aw_prot; | |
| axi_pkg::qos_t aw_qos; | |
| axi_pkg::region_t aw_region; | |
| axi_pkg::atop_t aw_atop; | |
| user_t aw_user; | |
| buffer_t aw_writetoken; | |
| buffer_t aw_readpointer; | |
| data_t w_data; | |
| strb_t w_strb; | |
| logic w_last; | |
| user_t w_user; | |
| buffer_t w_writetoken; | |
| buffer_t w_readpointer; | |
| id_t b_id; | |
| axi_pkg::resp_t b_resp; | |
| user_t b_user; | |
| buffer_t b_writetoken; | |
| buffer_t b_readpointer; | |
| id_t ar_id; | |
| addr_t ar_addr; | |
| axi_pkg::len_t ar_len; | |
| axi_pkg::size_t ar_size; | |
| axi_pkg::burst_t ar_burst; | |
| logic ar_lock; | |
| axi_pkg::cache_t ar_cache; | |
| axi_pkg::prot_t ar_prot; | |
| axi_pkg::qos_t ar_qos; | |
| axi_pkg::region_t ar_region; | |
| user_t ar_user; | |
| buffer_t ar_writetoken; | |
| buffer_t ar_readpointer; | |
| id_t r_id; | |
| data_t r_data; | |
| axi_pkg::resp_t r_resp; | |
| logic r_last; | |
| user_t r_user; | |
| buffer_t r_writetoken; | |
| buffer_t r_readpointer; | |
| modport Master ( | |
| output aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_writetoken, input aw_readpointer, | |
| output w_data, w_strb, w_last, w_user, w_writetoken, input w_readpointer, | |
| input b_id, b_resp, b_user, b_writetoken, output b_readpointer, | |
| output ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_writetoken, input ar_readpointer, | |
| input r_id, r_data, r_resp, r_last, r_user, r_writetoken, output r_readpointer | |
| ); | |
| modport Slave ( | |
| input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_writetoken, output aw_readpointer, | |
| input w_data, w_strb, w_last, w_user, w_writetoken, output w_readpointer, | |
| output b_id, b_resp, b_user, b_writetoken, input b_readpointer, | |
| input ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_writetoken, output ar_readpointer, | |
| output r_id, r_data, r_resp, r_last, r_user, r_writetoken, input r_readpointer | |
| ); | |
| endinterface | |
| interface AXI_BUS_ASYNC_GRAY #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0, | |
| parameter int unsigned LOG_DEPTH = 0 | |
| ); | |
| localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_STRB_WIDTH-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| aw_chan_t [2**LOG_DEPTH-1:0] aw_data; | |
| w_chan_t [2**LOG_DEPTH-1:0] w_data; | |
| b_chan_t [2**LOG_DEPTH-1:0] b_data; | |
| ar_chan_t [2**LOG_DEPTH-1:0] ar_data; | |
| r_chan_t [2**LOG_DEPTH-1:0] r_data; | |
| logic [LOG_DEPTH:0] aw_wptr, aw_rptr, | |
| w_wptr, w_rptr, | |
| b_wptr, b_rptr, | |
| ar_wptr, ar_rptr, | |
| r_wptr, r_rptr; | |
| modport Master ( | |
| output aw_data, aw_wptr, input aw_rptr, | |
| output w_data, w_wptr, input w_rptr, | |
| input b_data, b_wptr, output b_rptr, | |
| output ar_data, ar_wptr, input ar_rptr, | |
| input r_data, r_wptr, output r_rptr); | |
| modport Slave ( | |
| input aw_data, aw_wptr, output aw_rptr, | |
| input w_data, w_wptr, output w_rptr, | |
| output b_data, b_wptr, input b_rptr, | |
| input ar_data, ar_wptr, output ar_rptr, | |
| output r_data, r_wptr, input r_rptr); | |
| endinterface | |
| interface AXI_LITE #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0 | |
| ); | |
| localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_STRB_WIDTH-1:0] strb_t; | |
| addr_t aw_addr; | |
| axi_pkg::prot_t aw_prot; | |
| logic aw_valid; | |
| logic aw_ready; | |
| data_t w_data; | |
| strb_t w_strb; | |
| logic w_valid; | |
| logic w_ready; | |
| axi_pkg::resp_t b_resp; | |
| logic b_valid; | |
| logic b_ready; | |
| addr_t ar_addr; | |
| axi_pkg::prot_t ar_prot; | |
| logic ar_valid; | |
| logic ar_ready; | |
| data_t r_data; | |
| axi_pkg::resp_t r_resp; | |
| logic r_valid; | |
| logic r_ready; | |
| modport Master ( | |
| output aw_addr, aw_prot, aw_valid, input aw_ready, | |
| output w_data, w_strb, w_valid, input w_ready, | |
| input b_resp, b_valid, output b_ready, | |
| output ar_addr, ar_prot, ar_valid, input ar_ready, | |
| input r_data, r_resp, r_valid, output r_ready | |
| ); | |
| modport Slave ( | |
| input aw_addr, aw_prot, aw_valid, output aw_ready, | |
| input w_data, w_strb, w_valid, output w_ready, | |
| output b_resp, b_valid, input b_ready, | |
| input ar_addr, ar_prot, ar_valid, output ar_ready, | |
| output r_data, r_resp, r_valid, input r_ready | |
| ); | |
| modport Monitor ( | |
| input aw_addr, aw_prot, aw_valid, aw_ready, | |
| w_data, w_strb, w_valid, w_ready, | |
| b_resp, b_valid, b_ready, | |
| ar_addr, ar_prot, ar_valid, ar_ready, | |
| r_data, r_resp, r_valid, r_ready | |
| ); | |
| endinterface | |
| interface AXI_LITE_DV #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0 | |
| )( | |
| input logic clk_i | |
| ); | |
| localparam AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_STRB_WIDTH-1:0] strb_t; | |
| addr_t aw_addr; | |
| axi_pkg::prot_t aw_prot; | |
| logic aw_valid; | |
| logic aw_ready; | |
| data_t w_data; | |
| strb_t w_strb; | |
| logic w_valid; | |
| logic w_ready; | |
| axi_pkg::resp_t b_resp; | |
| logic b_valid; | |
| logic b_ready; | |
| addr_t ar_addr; | |
| axi_pkg::prot_t ar_prot; | |
| logic ar_valid; | |
| logic ar_ready; | |
| data_t r_data; | |
| axi_pkg::resp_t r_resp; | |
| logic r_valid; | |
| logic r_ready; | |
| modport Master ( | |
| output aw_addr, aw_prot, aw_valid, input aw_ready, | |
| output w_data, w_strb, w_valid, input w_ready, | |
| input b_resp, b_valid, output b_ready, | |
| output ar_addr, ar_prot, ar_valid, input ar_ready, | |
| input r_data, r_resp, r_valid, output r_ready | |
| ); | |
| modport Slave ( | |
| input aw_addr, aw_prot, aw_valid, output aw_ready, | |
| input w_data, w_strb, w_valid, output w_ready, | |
| output b_resp, b_valid, input b_ready, | |
| input ar_addr, ar_prot, ar_valid, output ar_ready, | |
| output r_data, r_resp, r_valid, input r_ready | |
| ); | |
| modport Monitor ( | |
| input aw_addr, aw_prot, aw_valid, aw_ready, | |
| w_data, w_strb, w_valid, w_ready, | |
| b_resp, b_valid, b_ready, | |
| ar_addr, ar_prot, ar_valid, ar_ready, | |
| r_data, r_resp, r_valid, r_ready | |
| ); | |
| endinterface | |
| interface AXI_LITE_ASYNC_GRAY #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned LOG_DEPTH = 0 | |
| ); | |
| localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_STRB_WIDTH-1:0] strb_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_t; | |
| aw_chan_t [2**LOG_DEPTH-1:0] aw_data; | |
| w_chan_t [2**LOG_DEPTH-1:0] w_data; | |
| b_chan_t [2**LOG_DEPTH-1:0] b_data; | |
| ar_chan_t [2**LOG_DEPTH-1:0] ar_data; | |
| r_chan_t [2**LOG_DEPTH-1:0] r_data; | |
| logic [LOG_DEPTH:0] aw_wptr, aw_rptr, | |
| w_wptr, w_rptr, | |
| b_wptr, b_rptr, | |
| ar_wptr, ar_rptr, | |
| r_wptr, r_rptr; | |
| modport Master ( | |
| output aw_data, aw_wptr, input aw_rptr, | |
| output w_data, w_wptr, input w_rptr, | |
| input b_data, b_wptr, output b_rptr, | |
| output ar_data, ar_wptr, input ar_rptr, | |
| input r_data, r_wptr, output r_rptr); | |
| modport Slave ( | |
| input aw_data, aw_wptr, output aw_rptr, | |
| input w_data, w_wptr, output w_rptr, | |
| output b_data, b_wptr, input b_rptr, | |
| input ar_data, ar_wptr, output ar_rptr, | |
| output r_data, r_wptr, input r_rptr); | |
| endinterface | |
| `begin_keywords "1800-2023" | |
| module axi_atop_filter #( | |
| parameter int unsigned AxiIdWidth = 0, | |
| parameter int unsigned AxiMaxWriteTxns = 0, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| localparam int unsigned COUNTER_WIDTH = (AxiMaxWriteTxns == 1) ? 2 : $clog2(AxiMaxWriteTxns+1); | |
| typedef struct packed { | |
| logic underflow; | |
| logic [COUNTER_WIDTH-1:0] cnt; | |
| } cnt_t; | |
| cnt_t w_cnt_d, w_cnt_q; | |
| typedef enum logic [2:0] { | |
| W_RESET, W_FEEDTHROUGH, BLOCK_AW, ABSORB_W, HOLD_B, INJECT_B, WAIT_R | |
| } w_state_e; | |
| w_state_e w_state_d, w_state_q; | |
| typedef enum logic [1:0] { R_RESET, R_FEEDTHROUGH, INJECT_R, R_HOLD } r_state_e; | |
| r_state_e r_state_d, r_state_q; | |
| typedef logic [AxiIdWidth-1:0] id_t; | |
| id_t id_d, id_q; | |
| typedef logic [7:0] len_t; | |
| len_t r_beats_d, r_beats_q; | |
| typedef struct packed { | |
| len_t len; | |
| } r_resp_cmd_t; | |
| r_resp_cmd_t r_resp_cmd_push, r_resp_cmd_pop; | |
| logic aw_without_complete_w_downstream, | |
| complete_w_without_aw_downstream, | |
| r_resp_cmd_push_valid, r_resp_cmd_push_ready, | |
| r_resp_cmd_pop_valid, r_resp_cmd_pop_ready; | |
| assign aw_without_complete_w_downstream = !w_cnt_q.underflow && (w_cnt_q.cnt > 0); | |
| assign complete_w_without_aw_downstream = w_cnt_q.underflow && &(w_cnt_q.cnt); | |
| always_comb begin | |
| mst_req_o.aw_valid = 1'b0; | |
| slv_resp_o.aw_ready = 1'b0; | |
| mst_req_o.w_valid = 1'b0; | |
| slv_resp_o.w_ready = 1'b0; | |
| mst_req_o.b_ready = slv_req_i.b_ready; | |
| slv_resp_o.b_valid = mst_resp_i.b_valid; | |
| slv_resp_o.b = mst_resp_i.b; | |
| id_d = id_q; | |
| r_resp_cmd_push_valid = 1'b0; | |
| w_state_d = w_state_q; | |
| unique case (w_state_q) | |
| W_RESET: w_state_d = W_FEEDTHROUGH; | |
| W_FEEDTHROUGH: begin | |
| if (complete_w_without_aw_downstream || (w_cnt_q.cnt < AxiMaxWriteTxns)) begin | |
| mst_req_o.aw_valid = slv_req_i.aw_valid; | |
| slv_resp_o.aw_ready = mst_resp_i.aw_ready; | |
| end | |
| if (aw_without_complete_w_downstream | |
| || ((slv_req_i.aw_valid && slv_req_i.aw.atop[5:4] == axi_pkg::ATOP_NONE) | |
| && !complete_w_without_aw_downstream) | |
| ) begin | |
| mst_req_o.w_valid = slv_req_i.w_valid; | |
| slv_resp_o.w_ready = mst_resp_i.w_ready; | |
| end | |
| if (slv_req_i.aw_valid && slv_req_i.aw.atop[5:4] != axi_pkg::ATOP_NONE) begin | |
| mst_req_o.aw_valid = 1'b0; | |
| slv_resp_o.aw_ready = 1'b1; | |
| id_d = slv_req_i.aw.id; | |
| if (slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP]) begin | |
| r_resp_cmd_push_valid = 1'b1; | |
| end | |
| if (aw_without_complete_w_downstream) begin | |
| w_state_d = BLOCK_AW; | |
| end else begin | |
| mst_req_o.w_valid = 1'b0; | |
| slv_resp_o.w_ready = 1'b1; | |
| if (slv_req_i.w_valid && slv_req_i.w.last) begin | |
| if (slv_resp_o.b_valid && !slv_req_i.b_ready) begin | |
| w_state_d = HOLD_B; | |
| end else begin | |
| w_state_d = INJECT_B; | |
| end | |
| end else begin | |
| w_state_d = ABSORB_W; | |
| end | |
| end | |
| end | |
| end | |
| BLOCK_AW: begin | |
| if (aw_without_complete_w_downstream) begin | |
| mst_req_o.w_valid = slv_req_i.w_valid; | |
| slv_resp_o.w_ready = mst_resp_i.w_ready; | |
| end else begin | |
| slv_resp_o.w_ready = 1'b1; | |
| if (slv_req_i.w_valid && slv_req_i.w.last) begin | |
| if (slv_resp_o.b_valid && !slv_req_i.b_ready) begin | |
| w_state_d = HOLD_B; | |
| end else begin | |
| w_state_d = INJECT_B; | |
| end | |
| end else begin | |
| w_state_d = ABSORB_W; | |
| end | |
| end | |
| end | |
| ABSORB_W: begin | |
| slv_resp_o.w_ready = 1'b1; | |
| if (slv_req_i.w_valid && slv_req_i.w.last) begin | |
| if (slv_resp_o.b_valid && !slv_req_i.b_ready) begin | |
| w_state_d = HOLD_B; | |
| end else begin | |
| w_state_d = INJECT_B; | |
| end | |
| end | |
| end | |
| HOLD_B: begin | |
| if (slv_resp_o.b_valid && slv_req_i.b_ready) begin | |
| w_state_d = INJECT_B; | |
| end | |
| end | |
| INJECT_B: begin | |
| mst_req_o.b_ready = 1'b0; | |
| slv_resp_o.b = '0; | |
| slv_resp_o.b.id = id_q; | |
| slv_resp_o.b.resp = axi_pkg::RESP_SLVERR; | |
| slv_resp_o.b_valid = 1'b1; | |
| if (slv_req_i.b_ready) begin | |
| if (r_resp_cmd_pop_valid && !r_resp_cmd_pop_ready) begin | |
| w_state_d = WAIT_R; | |
| end else begin | |
| w_state_d = W_FEEDTHROUGH; | |
| end | |
| end | |
| end | |
| WAIT_R: begin | |
| if (!r_resp_cmd_pop_valid) begin | |
| w_state_d = W_FEEDTHROUGH; | |
| end | |
| end | |
| default: w_state_d = W_RESET; | |
| endcase | |
| end | |
| always_comb begin | |
| mst_req_o.aw = slv_req_i.aw; | |
| mst_req_o.aw.atop = '0; | |
| end | |
| assign mst_req_o.w = slv_req_i.w; | |
| always_comb begin | |
| slv_resp_o.r = mst_resp_i.r; | |
| slv_resp_o.r_valid = mst_resp_i.r_valid; | |
| mst_req_o.r_ready = slv_req_i.r_ready; | |
| r_resp_cmd_pop_ready = 1'b0; | |
| r_beats_d = r_beats_q; | |
| r_state_d = r_state_q; | |
| unique case (r_state_q) | |
| R_RESET: r_state_d = R_FEEDTHROUGH; | |
| R_FEEDTHROUGH: begin | |
| if (mst_resp_i.r_valid && !slv_req_i.r_ready) begin | |
| r_state_d = R_HOLD; | |
| end else if (r_resp_cmd_pop_valid) begin | |
| r_beats_d = r_resp_cmd_pop.len; | |
| r_state_d = INJECT_R; | |
| end | |
| end | |
| INJECT_R: begin | |
| mst_req_o.r_ready = 1'b0; | |
| slv_resp_o.r = '0; | |
| slv_resp_o.r.id = id_q; | |
| slv_resp_o.r.resp = axi_pkg::RESP_SLVERR; | |
| slv_resp_o.r.last = (r_beats_q == '0); | |
| slv_resp_o.r_valid = 1'b1; | |
| if (slv_req_i.r_ready) begin | |
| if (slv_resp_o.r.last) begin | |
| r_resp_cmd_pop_ready = 1'b1; | |
| r_state_d = R_FEEDTHROUGH; | |
| end else begin | |
| r_beats_d -= 1; | |
| end | |
| end | |
| end | |
| R_HOLD: begin | |
| if (mst_resp_i.r_valid && slv_req_i.r_ready) begin | |
| r_state_d = R_FEEDTHROUGH; | |
| end | |
| end | |
| default: r_state_d = R_RESET; | |
| endcase | |
| end | |
| assign mst_req_o.ar = slv_req_i.ar; | |
| assign mst_req_o.ar_valid = slv_req_i.ar_valid; | |
| assign slv_resp_o.ar_ready = mst_resp_i.ar_ready; | |
| always_comb begin | |
| w_cnt_d = w_cnt_q; | |
| if (mst_req_o.aw_valid && mst_resp_i.aw_ready) begin | |
| w_cnt_d.cnt += 1; | |
| end | |
| if (mst_req_o.w_valid && mst_resp_i.w_ready && mst_req_o.w.last) begin | |
| w_cnt_d.cnt -= 1; | |
| end | |
| if (w_cnt_q.underflow && (w_cnt_d.cnt == '0)) begin | |
| w_cnt_d.underflow = 1'b0; | |
| end else if (w_cnt_q.cnt == '0 && &(w_cnt_d.cnt)) begin | |
| w_cnt_d.underflow = 1'b1; | |
| end | |
| end | |
| always_ff @(posedge clk_i, negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| id_q <= '0; | |
| r_beats_q <= '0; | |
| r_state_q <= R_RESET; | |
| w_cnt_q <= '{default: '0}; | |
| w_state_q <= W_RESET; | |
| end else begin | |
| id_q <= id_d; | |
| r_beats_q <= r_beats_d; | |
| r_state_q <= r_state_d; | |
| w_cnt_q <= w_cnt_d; | |
| w_state_q <= w_state_d; | |
| end | |
| end | |
| stream_register #( | |
| .T(r_resp_cmd_t) | |
| ) r_resp_cmd ( | |
| .clk_i (clk_i), | |
| .rst_ni (rst_ni), | |
| .clr_i (1'b0), | |
| .testmode_i (1'b0), | |
| .valid_i (r_resp_cmd_push_valid), | |
| .ready_o (r_resp_cmd_push_ready), | |
| .data_i (r_resp_cmd_push), | |
| .valid_o (r_resp_cmd_pop_valid), | |
| .ready_i (r_resp_cmd_pop_ready), | |
| .data_o (r_resp_cmd_pop) | |
| ); | |
| assign r_resp_cmd_push.len = slv_req_i.aw.len; | |
| endmodule | |
| module axi_atop_filter_intf #( | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0, | |
| parameter int unsigned AXI_MAX_WRITE_TXNS = 0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| AXI_BUS.Slave slv, | |
| AXI_BUS.Master mst | |
| ); | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| b_chan_t b; | |
| logic r_valid; | |
| r_chan_t r; | |
| } axi_resp_t; | |
| axi_req_t slv_req, mst_req; | |
| axi_resp_t slv_resp, mst_resp; | |
| assign slv_req.aw.id = slv.aw_id; | |
| assign slv_req.aw.addr = slv.aw_addr; | |
| assign slv_req.aw.len = slv.aw_len; | |
| assign slv_req.aw.size = slv.aw_size; | |
| assign slv_req.aw.burst = slv.aw_burst; | |
| assign slv_req.aw.lock = slv.aw_lock; | |
| assign slv_req.aw.cache = slv.aw_cache; | |
| assign slv_req.aw.prot = slv.aw_prot; | |
| assign slv_req.aw.qos = slv.aw_qos; | |
| assign slv_req.aw.region = slv.aw_region; | |
| assign slv_req.aw.atop = slv.aw_atop; | |
| assign slv_req.aw.user = slv.aw_user; | |
| assign slv_req.aw_valid = slv.aw_valid; | |
| assign slv_req.w.data = slv.w_data; | |
| assign slv_req.w.strb = slv.w_strb; | |
| assign slv_req.w.last = slv.w_last; | |
| assign slv_req.w.user = slv.w_user; | |
| assign slv_req.w_valid = slv.w_valid; | |
| assign slv_req.b_ready = slv.b_ready; | |
| assign slv_req.ar.id = slv.ar_id; | |
| assign slv_req.ar.addr = slv.ar_addr; | |
| assign slv_req.ar.len = slv.ar_len; | |
| assign slv_req.ar.size = slv.ar_size; | |
| assign slv_req.ar.burst = slv.ar_burst; | |
| assign slv_req.ar.lock = slv.ar_lock; | |
| assign slv_req.ar.cache = slv.ar_cache; | |
| assign slv_req.ar.prot = slv.ar_prot; | |
| assign slv_req.ar.qos = slv.ar_qos; | |
| assign slv_req.ar.region = slv.ar_region; | |
| assign slv_req.ar.user = slv.ar_user; | |
| assign slv_req.ar_valid = slv.ar_valid; | |
| assign slv_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = slv_resp.aw_ready; | |
| assign slv.ar_ready = slv_resp.ar_ready; | |
| assign slv.w_ready = slv_resp.w_ready; | |
| assign slv.b_valid = slv_resp.b_valid; | |
| assign slv.b_id = slv_resp.b.id; | |
| assign slv.b_resp = slv_resp.b.resp; | |
| assign slv.b_user = slv_resp.b.user; | |
| assign slv.r_valid = slv_resp.r_valid; | |
| assign slv.r_id = slv_resp.r.id; | |
| assign slv.r_data = slv_resp.r.data; | |
| assign slv.r_resp = slv_resp.r.resp; | |
| assign slv.r_last = slv_resp.r.last; | |
| assign slv.r_user = slv_resp.r.user; | |
| assign mst.aw_id = mst_req.aw.id; | |
| assign mst.aw_addr = mst_req.aw.addr; | |
| assign mst.aw_len = mst_req.aw.len; | |
| assign mst.aw_size = mst_req.aw.size; | |
| assign mst.aw_burst = mst_req.aw.burst; | |
| assign mst.aw_lock = mst_req.aw.lock; | |
| assign mst.aw_cache = mst_req.aw.cache; | |
| assign mst.aw_prot = mst_req.aw.prot; | |
| assign mst.aw_qos = mst_req.aw.qos; | |
| assign mst.aw_region = mst_req.aw.region; | |
| assign mst.aw_atop = mst_req.aw.atop; | |
| assign mst.aw_user = mst_req.aw.user; | |
| assign mst.aw_valid = mst_req.aw_valid; | |
| assign mst.w_data = mst_req.w.data; | |
| assign mst.w_strb = mst_req.w.strb; | |
| assign mst.w_last = mst_req.w.last; | |
| assign mst.w_user = mst_req.w.user; | |
| assign mst.w_valid = mst_req.w_valid; | |
| assign mst.b_ready = mst_req.b_ready; | |
| assign mst.ar_id = mst_req.ar.id; | |
| assign mst.ar_addr = mst_req.ar.addr; | |
| assign mst.ar_len = mst_req.ar.len; | |
| assign mst.ar_size = mst_req.ar.size; | |
| assign mst.ar_burst = mst_req.ar.burst; | |
| assign mst.ar_lock = mst_req.ar.lock; | |
| assign mst.ar_cache = mst_req.ar.cache; | |
| assign mst.ar_prot = mst_req.ar.prot; | |
| assign mst.ar_qos = mst_req.ar.qos; | |
| assign mst.ar_region = mst_req.ar.region; | |
| assign mst.ar_user = mst_req.ar.user; | |
| assign mst.ar_valid = mst_req.ar_valid; | |
| assign mst.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = mst.aw_ready; | |
| assign mst_resp.ar_ready = mst.ar_ready; | |
| assign mst_resp.w_ready = mst.w_ready; | |
| assign mst_resp.b_valid = mst.b_valid; | |
| assign mst_resp.b.id = mst.b_id; | |
| assign mst_resp.b.resp = mst.b_resp; | |
| assign mst_resp.b.user = mst.b_user; | |
| assign mst_resp.r_valid = mst.r_valid; | |
| assign mst_resp.r.id = mst.r_id; | |
| assign mst_resp.r.data = mst.r_data; | |
| assign mst_resp.r.resp = mst.r_resp; | |
| assign mst_resp.r.last = mst.r_last; | |
| assign mst_resp.r.user = mst.r_user; | |
| axi_atop_filter #( | |
| .AxiIdWidth ( AXI_ID_WIDTH ), | |
| .AxiMaxWriteTxns ( AXI_MAX_WRITE_TXNS ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ) | |
| ) i_axi_atop_filter ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_req ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_req_o ( mst_req ), | |
| .mst_resp_i ( mst_resp ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_burst_splitter_gran #( | |
| parameter int unsigned MaxReadTxns = 32'd0, | |
| parameter int unsigned MaxWriteTxns = 32'd0, | |
| parameter bit FullBW = 1'b0, | |
| parameter bit CutPath = 1'b0, | |
| parameter bit DisableChecks = 1'b0, | |
| parameter int unsigned AddrWidth = 32'd0, | |
| parameter int unsigned DataWidth = 32'd0, | |
| parameter int unsigned IdWidth = 32'd0, | |
| parameter int unsigned UserWidth = 32'd0, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic, | |
| parameter type axi_aw_chan_t = logic, | |
| parameter type axi_w_chan_t = logic, | |
| parameter type axi_b_chan_t = logic, | |
| parameter type axi_ar_chan_t = logic, | |
| parameter type axi_r_chan_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_pkg::len_t len_limit_i, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| axi_req_t slv_req, act_req, unsupported_req; | |
| axi_resp_t slv_resp, act_resp, unsupported_resp; | |
| axi_multicut #( | |
| .NoCuts ( CutPath ), | |
| .aw_chan_t ( axi_aw_chan_t ), | |
| .w_chan_t ( axi_w_chan_t ), | |
| .b_chan_t ( axi_b_chan_t ), | |
| .ar_chan_t ( axi_ar_chan_t ), | |
| .r_chan_t ( axi_r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t( axi_resp_t ) | |
| ) i_axi_multicut ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i , | |
| .slv_resp_o, | |
| .mst_req_o ( slv_req ), | |
| .mst_resp_i ( slv_resp ) | |
| ); | |
| logic sel_aw_unsupported, sel_ar_unsupported; | |
| localparam int unsigned MaxTxns = (MaxReadTxns > MaxWriteTxns) ? MaxReadTxns : MaxWriteTxns; | |
| axi_demux_simple #( | |
| .AxiIdWidth ( IdWidth ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .NoMstPorts ( 2 ), | |
| .MaxTrans ( MaxTxns ), | |
| .AxiLookBits ( IdWidth ) | |
| ) i_demux_supported_vs_unsupported ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i ( 1'b0 ), | |
| .slv_req_i ( slv_req ), | |
| .slv_aw_select_i ( sel_aw_unsupported ), | |
| .slv_ar_select_i ( sel_ar_unsupported ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_reqs_o ( {unsupported_req, act_req} ), | |
| .mst_resps_i ( {unsupported_resp, act_resp} ) | |
| ); | |
| function bit txn_supported(axi_pkg::atop_t atop, axi_pkg::burst_t burst, axi_pkg::cache_t cache, | |
| axi_pkg::len_t len, axi_pkg::len_t len_limit); | |
| if (len >= len_limit) begin | |
| return 1'b1; | |
| end else begin | |
| if (burst == axi_pkg::BURST_WRAP) return 1'b0; | |
| if (atop != '0 & len > 0) return 1'b0; | |
| if (!axi_pkg::modifiable(cache)) begin | |
| return (burst == axi_pkg::BURST_INCR) & (len > 16); | |
| end | |
| return 1'b1; | |
| end | |
| endfunction | |
| assign sel_aw_unsupported = DisableChecks ? 1'b0 : ~txn_supported(slv_req.aw.atop, | |
| slv_req.aw.burst, slv_req.aw.cache, slv_req.aw.len, | |
| len_limit_i); | |
| assign sel_ar_unsupported = DisableChecks ? 1'b0 : ~txn_supported('0, slv_req.ar.burst, | |
| slv_req.ar.cache, slv_req.ar.len, len_limit_i); | |
| axi_err_slv #( | |
| .AxiIdWidth ( IdWidth ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .Resp ( axi_pkg::RESP_SLVERR ), | |
| .ATOPs ( 1'b0 ), | |
| .MaxTrans ( 1 ) | |
| ) i_err_slv ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i ( 1'b0 ), | |
| .slv_req_i ( unsupported_req ), | |
| .slv_resp_o ( unsupported_resp ) | |
| ); | |
| logic w_cnt_dec, w_cnt_req, w_cnt_gnt, w_cnt_err; | |
| axi_pkg::len_t w_cnt_len; | |
| axi_burst_splitter_gran_ax_chan #( | |
| .chan_t ( axi_aw_chan_t ), | |
| .IdWidth ( IdWidth ), | |
| .MaxTxns ( MaxWriteTxns ), | |
| .CutPath ( CutPath ), | |
| .FullBW ( FullBW ) | |
| ) i_axi_burst_splitter_gran_aw_chan ( | |
| .clk_i, | |
| .rst_ni, | |
| .len_limit_i, | |
| .ax_i ( act_req.aw ), | |
| .ax_valid_i ( act_req.aw_valid ), | |
| .ax_ready_o ( act_resp.aw_ready ), | |
| .ax_o ( mst_req_o.aw ), | |
| .ax_valid_o ( mst_req_o.aw_valid ), | |
| .ax_ready_i ( mst_resp_i.aw_ready ), | |
| .cnt_id_i ( mst_resp_i.b.id ), | |
| .cnt_len_o ( w_cnt_len ), | |
| .cnt_set_err_i ( mst_resp_i.b.resp[1] ), | |
| .cnt_err_o ( w_cnt_err ), | |
| .cnt_dec_i ( w_cnt_dec ), | |
| .cnt_req_i ( w_cnt_req ), | |
| .cnt_gnt_o ( w_cnt_gnt ) | |
| ); | |
| axi_pkg::len_t w_len_d, w_len_q; | |
| logic w_len_vld_q, w_len_vld_d; | |
| always_comb begin : proc_w_frag | |
| mst_req_o.w = act_req.w; | |
| w_len_d = w_len_q; | |
| w_len_vld_d = w_len_vld_q; | |
| if (len_limit_i != 8'h00) begin | |
| mst_req_o.w.last = (w_len_vld_q & (w_len_q == 8'h00)) | act_req.w.last; | |
| if (act_resp.w_ready & act_req.w_valid) begin | |
| if (!w_len_vld_q) begin | |
| w_len_vld_d = 1'b1; | |
| w_len_d = len_limit_i - 8'h01; | |
| end else begin | |
| w_len_d = w_len_q - 8'h01; | |
| if (w_len_q == 8'h00) begin | |
| w_len_d = len_limit_i; | |
| end | |
| end | |
| if (act_req.w.last) begin | |
| w_len_vld_d = 1'b0; | |
| w_len_d = 8'h00; | |
| end | |
| end | |
| end else begin | |
| mst_req_o.w.last = 1'b1; | |
| end | |
| end | |
| assign mst_req_o.w_valid = act_req.w_valid; | |
| assign act_resp.w_ready = mst_resp_i.w_ready; | |
| enum logic {BReady, BWait} b_state_d, b_state_q; | |
| logic b_err_d, b_err_q; | |
| always_comb begin | |
| mst_req_o.b_ready = 1'b0; | |
| act_resp.b = '0; | |
| act_resp.b_valid = 1'b0; | |
| w_cnt_dec = 1'b0; | |
| w_cnt_req = 1'b0; | |
| b_err_d = b_err_q; | |
| b_state_d = b_state_q; | |
| unique case (b_state_q) | |
| BReady: begin | |
| if (mst_resp_i.b_valid) begin | |
| w_cnt_req = 1'b1; | |
| if (w_cnt_gnt) begin | |
| if (w_cnt_len < ({1'b0, len_limit_i} + 9'h001)) begin | |
| act_resp.b = mst_resp_i.b; | |
| if (w_cnt_err) begin | |
| act_resp.b.resp = axi_pkg::RESP_SLVERR; | |
| end | |
| act_resp.b_valid = 1'b1; | |
| w_cnt_dec = 1'b1; | |
| if (act_req.b_ready) begin | |
| mst_req_o.b_ready = 1'b1; | |
| end else begin | |
| b_state_d = BWait; | |
| b_err_d = w_cnt_err; | |
| end | |
| end else begin | |
| mst_req_o.b_ready = 1'b1; | |
| w_cnt_dec = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| BWait: begin | |
| act_resp.b = mst_resp_i.b; | |
| if (b_err_q) begin | |
| act_resp.b.resp = axi_pkg::RESP_SLVERR; | |
| end | |
| act_resp.b_valid = 1'b1; | |
| if (mst_resp_i.b_valid && act_req.b_ready) begin | |
| mst_req_o.b_ready = 1'b1; | |
| b_state_d = BReady; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| logic r_cnt_dec, r_cnt_req, r_cnt_gnt; | |
| axi_pkg::len_t r_cnt_len; | |
| axi_burst_splitter_gran_ax_chan #( | |
| .chan_t ( axi_ar_chan_t ), | |
| .IdWidth ( IdWidth ), | |
| .MaxTxns ( MaxReadTxns ), | |
| .CutPath ( CutPath ), | |
| .FullBW ( FullBW ) | |
| ) i_axi_burst_splitter_gran_ar_chan ( | |
| .clk_i, | |
| .rst_ni, | |
| .len_limit_i, | |
| .ax_i ( act_req.ar ), | |
| .ax_valid_i ( act_req.ar_valid ), | |
| .ax_ready_o ( act_resp.ar_ready ), | |
| .ax_o ( mst_req_o.ar ), | |
| .ax_valid_o ( mst_req_o.ar_valid ), | |
| .ax_ready_i ( mst_resp_i.ar_ready ), | |
| .cnt_id_i ( mst_resp_i.r.id ), | |
| .cnt_len_o ( r_cnt_len ), | |
| .cnt_set_err_i ( 1'b0 ), | |
| .cnt_err_o ( ), | |
| .cnt_dec_i ( r_cnt_dec ), | |
| .cnt_req_i ( r_cnt_req ), | |
| .cnt_gnt_o ( r_cnt_gnt ) | |
| ); | |
| logic r_last_d, r_last_q; | |
| enum logic {RFeedthrough, RWait} r_state_d, r_state_q; | |
| always_comb begin | |
| r_cnt_dec = 1'b0; | |
| r_cnt_req = 1'b0; | |
| r_last_d = r_last_q; | |
| r_state_d = r_state_q; | |
| mst_req_o.r_ready = 1'b0; | |
| act_resp.r = mst_resp_i.r; | |
| act_resp.r.last = 1'b0; | |
| act_resp.r_valid = 1'b0; | |
| unique case (r_state_q) | |
| RFeedthrough: begin | |
| if (mst_resp_i.r_valid) begin | |
| if (mst_resp_i.r.last) begin | |
| r_cnt_req = 1'b1; | |
| if (r_cnt_gnt) begin | |
| r_last_d = (r_cnt_len < ({1'b0, len_limit_i} + 9'h001)); | |
| act_resp.r.last = r_last_d; | |
| r_cnt_dec = 1'b1; | |
| act_resp.r_valid = 1'b1; | |
| if (act_req.r_ready) begin | |
| mst_req_o.r_ready = 1'b1; | |
| end else begin | |
| r_state_d = RWait; | |
| end | |
| end | |
| end else begin | |
| r_last_d = 1'b0; | |
| act_resp.r.last = r_last_d; | |
| act_resp.r_valid = 1'b1; | |
| if (act_req.r_ready) begin | |
| mst_req_o.r_ready = 1'b1; | |
| end else begin | |
| r_state_d = RWait; | |
| end | |
| end | |
| end | |
| end | |
| RWait: begin | |
| act_resp.r.last = r_last_q; | |
| act_resp.r_valid = mst_resp_i.r_valid; | |
| if (mst_resp_i.r_valid && act_req.r_ready) begin | |
| mst_req_o.r_ready = 1'b1; | |
| r_state_d = RFeedthrough; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| b_err_q <= (1'b0); | |
| end else begin | |
| b_err_q <= (b_err_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| b_state_q <= (BReady); | |
| end else begin | |
| b_state_q <= (b_state_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| r_last_q <= (1'b0); | |
| end else begin | |
| r_last_q <= (r_last_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| r_state_q <= (RFeedthrough); | |
| end else begin | |
| r_state_q <= (r_state_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| w_len_q <= (8'h00); | |
| end else begin | |
| w_len_q <= (w_len_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| w_len_vld_q <= (1'b0); | |
| end else begin | |
| w_len_vld_q <= (w_len_vld_d); | |
| end | |
| end | |
| endmodule | |
| module axi_burst_splitter_gran_ax_chan #( | |
| parameter type chan_t = logic, | |
| parameter int unsigned IdWidth = 32'd0, | |
| parameter int unsigned MaxTxns = 32'd0, | |
| parameter bit CutPath = 1'b0, | |
| parameter bit FullBW = 1'b0, | |
| parameter type id_t = logic[IdWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_pkg::len_t len_limit_i, | |
| input chan_t ax_i, | |
| input logic ax_valid_i, | |
| output logic ax_ready_o, | |
| output chan_t ax_o, | |
| output logic ax_valid_o, | |
| input logic ax_ready_i, | |
| input id_t cnt_id_i, | |
| output axi_pkg::len_t cnt_len_o, | |
| input logic cnt_set_err_i, | |
| output logic cnt_err_o, | |
| input logic cnt_dec_i, | |
| input logic cnt_req_i, | |
| output logic cnt_gnt_o | |
| ); | |
| typedef logic[IdWidth-1:0] cnt_id_t; | |
| typedef logic[axi_pkg::LenWidth:0] num_beats_t; | |
| chan_t ax_d, ax_q; | |
| num_beats_t num_beats_d, num_beats_q; | |
| num_beats_t max_beats; | |
| logic cnt_alloc_req, cnt_alloc_gnt; | |
| axi_burst_splitter_gran_counters #( | |
| .MaxTxns ( MaxTxns ), | |
| .IdWidth ( IdWidth ), | |
| .CutPath ( CutPath ), | |
| .FullBW ( FullBW ) | |
| ) i_axi_burst_splitter_gran_counters ( | |
| .clk_i, | |
| .rst_ni, | |
| .alloc_id_i ( ax_i.id ), | |
| .alloc_len_i ( ax_i.len ), | |
| .alloc_req_i ( cnt_alloc_req ), | |
| .alloc_gnt_o ( cnt_alloc_gnt ), | |
| .cnt_id_i ( cnt_id_i ), | |
| .cnt_len_o ( cnt_len_o ), | |
| .cnt_set_err_i ( cnt_set_err_i ), | |
| .cnt_err_o ( cnt_err_o ), | |
| .cnt_dec_i ( cnt_dec_i ), | |
| .cnt_delta_i ( max_beats ), | |
| .cnt_req_i ( cnt_req_i ), | |
| .cnt_gnt_o ( cnt_gnt_o ) | |
| ); | |
| assign max_beats = {1'b0, len_limit_i} + 9'h001; | |
| enum logic {Idle, Busy} state_d, state_q; | |
| always_comb begin | |
| cnt_alloc_req = 1'b0; | |
| ax_d = ax_q; | |
| state_d = state_q; | |
| num_beats_d = num_beats_q; | |
| ax_o = '0; | |
| ax_valid_o = 1'b0; | |
| ax_ready_o = 1'b0; | |
| unique case (state_q) | |
| Idle: begin | |
| if (ax_valid_i && cnt_alloc_gnt) begin | |
| if (ax_i.len <= len_limit_i) begin | |
| ax_o = ax_i; | |
| ax_valid_o = 1'b1; | |
| if (ax_ready_i) begin | |
| cnt_alloc_req = 1'b1; | |
| ax_ready_o = 1'b1; | |
| end | |
| end else begin | |
| ax_d = ax_i; | |
| cnt_alloc_req = 1'b1; | |
| ax_ready_o = 1'b1; | |
| state_d = Busy; | |
| num_beats_d = ({1'b0, ax_i.len} + 9'h001); | |
| ax_o = ax_d; | |
| ax_o.len = len_limit_i; | |
| ax_valid_o = 1'b1; | |
| if (ax_ready_i) begin | |
| num_beats_d = ({1'b0, ax_i.len} + 9'h001) - max_beats; | |
| if (ax_d.burst == axi_pkg::BURST_INCR) begin | |
| ax_d.addr = axi_pkg::aligned_addr(axi_pkg::largest_addr_t'(ax_d.addr), ax_d.size); | |
| ax_d.addr += (1 << ax_d.size) * max_beats; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| Busy: begin | |
| ax_o = ax_q; | |
| ax_valid_o = 1'b1; | |
| if (num_beats_q <= max_beats) begin | |
| ax_o.len = axi_pkg::len_t'(num_beats_q - 9'h001); | |
| end else begin | |
| ax_o.len = len_limit_i; | |
| end | |
| if (ax_ready_i) begin | |
| if (num_beats_q <= max_beats) begin | |
| state_d = Idle; | |
| end else begin | |
| num_beats_d = num_beats_q - max_beats; | |
| if (ax_q.burst == axi_pkg::BURST_INCR) begin | |
| ax_d.addr = axi_pkg::aligned_addr(axi_pkg::largest_addr_t'(ax_q.addr), ax_q.size); | |
| ax_d.addr += (1 << ax_q.size) * max_beats; | |
| end | |
| end | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| ax_q <= ('0); | |
| end else begin | |
| ax_q <= (ax_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| state_q <= (Idle); | |
| end else begin | |
| state_q <= (state_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| num_beats_q <= (9'h000); | |
| end else begin | |
| num_beats_q <= (num_beats_d); | |
| end | |
| end | |
| endmodule | |
| module axi_burst_splitter_gran_counters #( | |
| parameter int unsigned MaxTxns = 32'd0, | |
| parameter int unsigned IdWidth = 32'd0, | |
| parameter bit CutPath = 1'b0, | |
| parameter bit FullBW = 1'b0, | |
| parameter type id_t = logic [IdWidth-1:0], | |
| parameter type cnt_t = logic [axi_pkg::LenWidth:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input id_t alloc_id_i, | |
| input axi_pkg::len_t alloc_len_i, | |
| input logic alloc_req_i, | |
| output logic alloc_gnt_o, | |
| input id_t cnt_id_i, | |
| output axi_pkg::len_t cnt_len_o, | |
| input logic cnt_set_err_i, | |
| output logic cnt_err_o, | |
| input logic cnt_dec_i, | |
| input cnt_t cnt_delta_i, | |
| input logic cnt_req_i, | |
| output logic cnt_gnt_o | |
| ); | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::len_t len; | |
| } alloc_pld_t; | |
| alloc_pld_t alloc_pld_in, alloc_pld_out; | |
| logic alloc_req; | |
| logic alloc_gnt; | |
| assign alloc_pld_in.id = alloc_id_i; | |
| assign alloc_pld_in.len = alloc_len_i; | |
| if (CutPath) begin : gen_spill | |
| spill_register #( | |
| .T ( alloc_pld_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_spill_register_alloc ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( alloc_req_i ), | |
| .ready_o ( alloc_gnt_o ), | |
| .data_i ( alloc_pld_in ), | |
| .valid_o ( alloc_req ), | |
| .ready_i ( alloc_gnt ), | |
| .data_o ( alloc_pld_out ) | |
| ); | |
| end else begin : gen_no_spill | |
| assign alloc_req = alloc_req_i; | |
| assign alloc_gnt_o = alloc_gnt; | |
| assign alloc_pld_out = alloc_pld_in; | |
| end | |
| localparam int unsigned CntIdxWidth = (MaxTxns > 1) ? $clog2(MaxTxns) : 32'd1; | |
| typedef logic [CntIdxWidth-1:0] cnt_idx_t; | |
| logic [MaxTxns-1:0] cnt_dec, cnt_free, cnt_set, err_d, err_q, cnt_clr; | |
| cnt_t cnt_inp; | |
| cnt_t [MaxTxns-1:0] cnt_oup; | |
| cnt_idx_t cnt_free_idx, cnt_r_idx; | |
| for (genvar i = 0; i < MaxTxns; i++) begin : gen_cnt | |
| delta_counter #( | |
| .WIDTH ( $bits(cnt_t) ) | |
| ) i_cnt ( | |
| .clk_i, | |
| .rst_ni, | |
| .clear_i ( cnt_clr[i] ), | |
| .en_i ( cnt_dec[i] ), | |
| .load_i ( cnt_set[i] ), | |
| .down_i ( 1'b1 ), | |
| .delta_i ( cnt_delta_i ), | |
| .d_i ( cnt_inp ), | |
| .q_o ( cnt_oup[i] ), | |
| .overflow_o ( cnt_clr[i] ) | |
| ); | |
| assign cnt_free[i] = (cnt_oup[i] == '0); | |
| end | |
| assign cnt_inp = {1'b0, alloc_pld_out.len} + 1; | |
| lzc #( | |
| .WIDTH ( MaxTxns ), | |
| .MODE ( 1'b0 ) | |
| ) i_lzc ( | |
| .in_i ( cnt_free ), | |
| .cnt_o ( cnt_free_idx ), | |
| .empty_o ( ) | |
| ); | |
| logic idq_inp_req, idq_inp_gnt, | |
| idq_oup_gnt, idq_oup_valid, idq_oup_pop; | |
| id_queue #( | |
| .ID_WIDTH ( $bits(id_t) ), | |
| .CAPACITY ( MaxTxns ), | |
| .FULL_BW ( FullBW ), | |
| .data_t ( cnt_idx_t ) | |
| ) i_idq ( | |
| .clk_i, | |
| .rst_ni, | |
| .inp_id_i ( alloc_pld_out.id ), | |
| .inp_data_i ( cnt_free_idx ), | |
| .inp_req_i ( idq_inp_req ), | |
| .inp_gnt_o ( idq_inp_gnt ), | |
| .exists_data_i ( '0 ), | |
| .exists_mask_i ( '0 ), | |
| .exists_req_i ( 1'b0 ), | |
| .exists_o ( ), | |
| .exists_gnt_o ( ), | |
| .oup_id_i ( cnt_id_i ), | |
| .oup_pop_i ( idq_oup_pop ), | |
| .oup_req_i ( cnt_req_i ), | |
| .oup_data_o ( cnt_r_idx ), | |
| .oup_data_valid_o ( idq_oup_valid ), | |
| .oup_gnt_o ( idq_oup_gnt ), | |
| .full_o ( ), | |
| .empty_o ( ) | |
| ); | |
| assign idq_inp_req = alloc_req & alloc_gnt; | |
| assign alloc_gnt = idq_inp_gnt & |(cnt_free); | |
| assign cnt_gnt_o = idq_oup_gnt & idq_oup_valid; | |
| logic [8:0] read_len; | |
| assign read_len = cnt_oup[cnt_r_idx] - 1; | |
| assign cnt_len_o = read_len[7:0]; | |
| assign idq_oup_pop = cnt_req_i & cnt_gnt_o & cnt_dec_i & (cnt_len_o < cnt_delta_i); | |
| always_comb begin | |
| cnt_dec = '0; | |
| cnt_dec[cnt_r_idx] = cnt_req_i & cnt_gnt_o & cnt_dec_i; | |
| end | |
| always_comb begin | |
| cnt_set = '0; | |
| cnt_set[cnt_free_idx] = alloc_req & alloc_gnt; | |
| end | |
| always_comb begin | |
| err_d = err_q; | |
| cnt_err_o = err_q[cnt_r_idx]; | |
| if (cnt_req_i && cnt_gnt_o && cnt_set_err_i) begin | |
| err_d[cnt_r_idx] = 1'b1; | |
| cnt_err_o = 1'b1; | |
| end | |
| if (alloc_req && alloc_gnt) begin | |
| err_d[cnt_free_idx] = 1'b0; | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| err_q <= ('0); | |
| end else begin | |
| err_q <= (err_d); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_burst_unwrap #( | |
| parameter int unsigned MaxReadTxns = 32'd0, | |
| parameter int unsigned MaxWriteTxns = 32'd0, | |
| parameter int unsigned AddrWidth = 32'd0, | |
| parameter int unsigned DataWidth = 32'd0, | |
| parameter int unsigned IdWidth = 32'd0, | |
| parameter int unsigned UserWidth = 32'd0, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| typedef logic [AddrWidth-1:0] addr_t; | |
| typedef logic [DataWidth-1:0] data_t; | |
| typedef logic [IdWidth-1:0] id_t; | |
| typedef logic [DataWidth/8-1:0] strb_t; | |
| typedef logic [UserWidth-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| axi_req_t act_req, unsupported_req; | |
| axi_resp_t act_resp, unsupported_resp; | |
| logic sel_aw_unsupported, sel_ar_unsupported; | |
| localparam int unsigned MaxTxns = (MaxReadTxns > MaxWriteTxns) ? MaxReadTxns : MaxWriteTxns; | |
| axi_demux #( | |
| .AxiIdWidth ( IdWidth ), | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .NoMstPorts ( 2 ), | |
| .MaxTrans ( MaxTxns ), | |
| .AxiLookBits ( IdWidth ), | |
| .SpillAw ( 1'b0 ), | |
| .SpillW ( 1'b0 ), | |
| .SpillB ( 1'b0 ), | |
| .SpillAr ( 1'b0 ), | |
| .SpillR ( 1'b0 ) | |
| ) i_demux_supported_vs_unsupported ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i ( 1'b0 ), | |
| .slv_req_i, | |
| .slv_aw_select_i ( sel_aw_unsupported ), | |
| .slv_ar_select_i ( sel_ar_unsupported ), | |
| .slv_resp_o, | |
| .mst_reqs_o ( {unsupported_req, act_req} ), | |
| .mst_resps_i ( {unsupported_resp, act_resp} ) | |
| ); | |
| function bit txn_supported(axi_pkg::atop_t atop, axi_pkg::burst_t burst, axi_pkg::cache_t cache, | |
| axi_pkg::len_t len); | |
| if (len == '0) return 1'b1; | |
| if (atop != '0) return 1'b0; | |
| if (!axi_pkg::modifiable(cache) && (burst == axi_pkg::BURST_WRAP)) begin | |
| return 1'b0; | |
| end | |
| return 1'b1; | |
| endfunction | |
| assign sel_aw_unsupported = ~txn_supported(slv_req_i.aw.atop, slv_req_i.aw.burst, | |
| slv_req_i.aw.cache, slv_req_i.aw.len); | |
| assign sel_ar_unsupported = ~txn_supported('0, slv_req_i.ar.burst, | |
| slv_req_i.ar.cache, slv_req_i.ar.len); | |
| axi_err_slv #( | |
| .AxiIdWidth ( IdWidth ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .Resp ( axi_pkg::RESP_SLVERR ), | |
| .ATOPs ( 1'b0 ), | |
| .MaxTrans ( 1 ) | |
| ) i_err_slv ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i ( 1'b0 ), | |
| .slv_req_i ( unsupported_req ), | |
| .slv_resp_o ( unsupported_resp ) | |
| ); | |
| logic b_cnt_dec, b_cnt_req, b_cnt_gnt, b_cnt_err; | |
| logic w_cnt_dec, w_cnt_req, w_cnt_gnt; | |
| axi_pkg::len_t b_cnt_len, w_cnt_len; | |
| axi_burst_unwrap_ax_chan #( | |
| .AwChan ( 1'b1 ), | |
| .chan_t ( aw_chan_t ), | |
| .AddrWidth ( AddrWidth ), | |
| .IdWidth ( IdWidth ), | |
| .MaxTxns ( MaxWriteTxns ) | |
| ) i_axi_burst_unwrap_aw_chan ( | |
| .clk_i, | |
| .rst_ni, | |
| .ax_i ( act_req.aw ), | |
| .ax_valid_i ( act_req.aw_valid ), | |
| .ax_ready_o ( act_resp.aw_ready ), | |
| .ax_o ( mst_req_o.aw ), | |
| .ax_valid_o ( mst_req_o.aw_valid ), | |
| .ax_ready_i ( mst_resp_i.aw_ready ), | |
| .cnt_id_i ( mst_resp_i.b.id ), | |
| .cnt_len_o ({ w_cnt_len , b_cnt_len }), | |
| .cnt_set_err_i ( mst_resp_i.b.resp[1] ), | |
| .cnt_err_o ( b_cnt_err ), | |
| .cnt_dec_i ({ w_cnt_dec , b_cnt_dec }), | |
| .cnt_req_i ({ w_cnt_req , b_cnt_req }), | |
| .cnt_gnt_o ({ w_cnt_gnt , b_cnt_gnt }) | |
| ); | |
| logic w_last_d, w_last_q; | |
| enum logic [1:0] {WReady, WWait, WFeedthrough} w_state_d, w_state_q; | |
| always_comb begin | |
| w_cnt_dec = 1'b0; | |
| w_cnt_req = 1'b0; | |
| w_last_d = w_last_q; | |
| w_state_d = w_state_q; | |
| mst_req_o.w_valid = 1'b0; | |
| mst_req_o.w = act_req.w; | |
| act_resp.w_ready = 1'b0; | |
| unique case (w_state_q) | |
| WReady: begin | |
| if (act_req.w_valid) begin | |
| w_cnt_req = 1'b1; | |
| if (w_cnt_gnt) begin | |
| w_last_d = act_req.w.last | (w_cnt_len == 8'd0); | |
| mst_req_o.w.last = w_last_d; | |
| w_cnt_dec = 1'b1; | |
| mst_req_o.w_valid = 1'b1; | |
| if (mst_resp_i.w_ready) begin | |
| act_resp.w_ready = 1'b1; | |
| if (w_last_d && !act_req.w.last) begin | |
| w_state_d = WFeedthrough; | |
| end | |
| end else begin | |
| w_state_d = WWait; | |
| end | |
| end | |
| end | |
| end | |
| WWait: begin | |
| mst_req_o.w.last = w_last_q; | |
| mst_req_o.w_valid = 1'b1; | |
| if (mst_resp_i.w_ready) begin | |
| act_resp.w_ready = 1'b1; | |
| w_state_d = (!w_last_q || act_req.w.last) ? WReady : WFeedthrough; | |
| end | |
| end | |
| WFeedthrough: begin | |
| mst_req_o.w_valid = act_req.w_valid; | |
| act_resp.w_ready = mst_resp_i.w_ready; | |
| if (act_req.w_valid && mst_resp_i.w_ready && act_req.w.last) begin | |
| w_state_d = WReady; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| enum logic {BReady, BWait} b_state_d, b_state_q; | |
| logic b_err_d, b_err_q; | |
| always_comb begin | |
| mst_req_o.b_ready = 1'b0; | |
| act_resp.b = '0; | |
| act_resp.b_valid = 1'b0; | |
| b_cnt_dec = 1'b0; | |
| b_cnt_req = 1'b0; | |
| b_err_d = b_err_q; | |
| b_state_d = b_state_q; | |
| unique case (b_state_q) | |
| BReady: begin | |
| if (mst_resp_i.b_valid) begin | |
| b_cnt_req = 1'b1; | |
| if (b_cnt_gnt) begin | |
| if (b_cnt_len == 8'd0) begin | |
| act_resp.b = mst_resp_i.b; | |
| if (b_cnt_err) begin | |
| act_resp.b.resp = axi_pkg::RESP_SLVERR; | |
| end | |
| act_resp.b_valid = 1'b1; | |
| b_cnt_dec = 1'b1; | |
| if (act_req.b_ready) begin | |
| mst_req_o.b_ready = 1'b1; | |
| end else begin | |
| b_state_d = BWait; | |
| b_err_d = b_cnt_err; | |
| end | |
| end else begin | |
| mst_req_o.b_ready = 1'b1; | |
| b_cnt_dec = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| BWait: begin | |
| act_resp.b = mst_resp_i.b; | |
| if (b_err_q) begin | |
| act_resp.b.resp = axi_pkg::RESP_SLVERR; | |
| end | |
| act_resp.b_valid = 1'b1; | |
| if (mst_resp_i.b_valid && act_req.b_ready) begin | |
| mst_req_o.b_ready = 1'b1; | |
| b_state_d = BReady; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| logic r_cnt_dec, r_cnt_req, r_cnt_gnt, unc0; | |
| axi_pkg::len_t r_cnt_len, unc1; | |
| axi_burst_unwrap_ax_chan #( | |
| .AwChan ( 0 ), | |
| .chan_t ( ar_chan_t ), | |
| .AddrWidth ( AddrWidth ), | |
| .IdWidth ( IdWidth ), | |
| .MaxTxns ( MaxReadTxns ) | |
| ) i_axi_burst_unwrap_ar_chan ( | |
| .clk_i, | |
| .rst_ni, | |
| .ax_i ( act_req.ar ), | |
| .ax_valid_i ( act_req.ar_valid ), | |
| .ax_ready_o ( act_resp.ar_ready ), | |
| .ax_o ( mst_req_o.ar ), | |
| .ax_valid_o ( mst_req_o.ar_valid ), | |
| .ax_ready_i ( mst_resp_i.ar_ready ), | |
| .cnt_id_i ( mst_resp_i.r.id ), | |
| .cnt_len_o ({ unc1 , r_cnt_len }), | |
| .cnt_set_err_i ( 1'b0 ), | |
| .cnt_err_o ( ), | |
| .cnt_dec_i ({ 1'b0 , r_cnt_dec }), | |
| .cnt_req_i ({ 1'b0 , r_cnt_req }), | |
| .cnt_gnt_o ({ unc0 , r_cnt_gnt }) | |
| ); | |
| logic r_last_d, r_last_q; | |
| enum logic {RFeedthrough, RWait} r_state_d, r_state_q; | |
| always_comb begin | |
| r_cnt_dec = 1'b0; | |
| r_cnt_req = 1'b0; | |
| r_last_d = r_last_q; | |
| r_state_d = r_state_q; | |
| mst_req_o.r_ready = 1'b0; | |
| act_resp.r = mst_resp_i.r; | |
| act_resp.r.last = 1'b0; | |
| act_resp.r_valid = 1'b0; | |
| unique case (r_state_q) | |
| RFeedthrough: begin | |
| if (mst_resp_i.r_valid) begin | |
| r_cnt_req = 1'b1; | |
| if (r_cnt_gnt) begin | |
| r_last_d = (r_cnt_len == 8'd0); | |
| act_resp.r.last = r_last_d; | |
| r_cnt_dec = 1'b1; | |
| act_resp.r_valid = 1'b1; | |
| if (act_req.r_ready) begin | |
| mst_req_o.r_ready = 1'b1; | |
| end else begin | |
| r_state_d = RWait; | |
| end | |
| end | |
| end | |
| end | |
| RWait: begin | |
| act_resp.r.last = r_last_q; | |
| act_resp.r_valid = mst_resp_i.r_valid; | |
| if (mst_resp_i.r_valid && act_req.r_ready) begin | |
| mst_req_o.r_ready = 1'b1; | |
| r_state_d = RFeedthrough; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| b_err_q <= (1'b0); | |
| end else begin | |
| b_err_q <= (b_err_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| b_state_q <= (BReady); | |
| end else begin | |
| b_state_q <= (b_state_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| r_last_q <= (1'b0); | |
| end else begin | |
| r_last_q <= (r_last_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| r_state_q <= (RFeedthrough); | |
| end else begin | |
| r_state_q <= (r_state_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| w_last_q <= (1'b0); | |
| end else begin | |
| w_last_q <= (w_last_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| w_state_q <= (WReady); | |
| end else begin | |
| w_state_q <= (w_state_d); | |
| end | |
| end | |
| endmodule | |
| module axi_burst_unwrap_ax_chan #( | |
| parameter bit AwChan = 0, | |
| parameter type chan_t = logic, | |
| parameter int unsigned AddrWidth = 0, | |
| parameter int unsigned IdWidth = 0, | |
| parameter int unsigned MaxTxns = 0, | |
| parameter type id_t = logic[IdWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input chan_t ax_i, | |
| input logic ax_valid_i, | |
| output logic ax_ready_o, | |
| output chan_t ax_o, | |
| output logic ax_valid_o, | |
| input logic ax_ready_i, | |
| input id_t cnt_id_i, | |
| output axi_pkg::len_t [1:0] cnt_len_o, | |
| input logic cnt_set_err_i, | |
| output logic cnt_err_o, | |
| input logic [1:0] cnt_dec_i, | |
| input logic [1:0] cnt_req_i, | |
| output logic [1:0] cnt_gnt_o | |
| ); | |
| typedef logic[IdWidth-1:0] cnt_id_t; | |
| logic [1:0] cnt_alloc_req, cnt_alloc_gnt; | |
| axi_pkg::len_t split_len, alloc_len_0; | |
| axi_burst_counters #( | |
| .MaxTxns ( MaxTxns ), | |
| .IdWidth ( IdWidth ) | |
| ) i_axi_burst_counters0 ( | |
| .clk_i, | |
| .rst_ni, | |
| .alloc_id_i ( ax_i.id ), | |
| .alloc_len_i ( alloc_len_0 ), | |
| .alloc_req_i ( cnt_alloc_req[0] ), | |
| .alloc_gnt_o ( cnt_alloc_gnt[0] ), | |
| .cnt_id_i ( cnt_id_i ), | |
| .cnt_len_o ( cnt_len_o[0] ), | |
| .cnt_set_err_i ( cnt_set_err_i ), | |
| .cnt_err_o ( cnt_err_o ), | |
| .cnt_dec_i ( cnt_dec_i[0] ), | |
| .cnt_req_i ( cnt_req_i[0] ), | |
| .cnt_gnt_o ( cnt_gnt_o[0] ) | |
| ); | |
| assign alloc_len_0 = AwChan ? split_len : ax_i.len; | |
| axi_burst_counters #( | |
| .MaxTxns ( MaxTxns ), | |
| .IdWidth ( 1 ) | |
| ) i_axi_burst_counters1 ( | |
| .clk_i, | |
| .rst_ni, | |
| .alloc_id_i ( 1'b0 ), | |
| .alloc_len_i ( ax_o.len ), | |
| .alloc_req_i ( cnt_alloc_req[1] ), | |
| .alloc_gnt_o ( cnt_alloc_gnt[1] ), | |
| .cnt_id_i ( 1'b0 ), | |
| .cnt_len_o ( cnt_len_o[1] ), | |
| .cnt_set_err_i ( 1'b0 ), | |
| .cnt_err_o ( ), | |
| .cnt_dec_i ( cnt_dec_i[1] ), | |
| .cnt_req_i ( cnt_req_i[1] ), | |
| .cnt_gnt_o ( cnt_gnt_o[1] ) | |
| ); | |
| chan_t ax_d, ax_q; | |
| logic [10:0] container_size; | |
| logic [AddrWidth-1:0] wrap_boundary; | |
| assign container_size = (ax_i.len + 1) << ax_i.size; | |
| assign wrap_boundary = ax_i.addr & ~(AddrWidth'(container_size) - 1); | |
| enum logic {Idle, Busy} state_d, state_q; | |
| always_comb begin | |
| cnt_alloc_req = '0; | |
| ax_d = ax_q; | |
| state_d = state_q; | |
| ax_o = '0; | |
| ax_valid_o = 1'b0; | |
| ax_ready_o = 1'b0; | |
| split_len = 8'd0; | |
| unique case (state_q) | |
| Idle: begin | |
| if (ax_valid_i && &cnt_alloc_gnt) begin | |
| if (ax_i.burst == axi_pkg::BURST_WRAP && ax_i.addr != wrap_boundary) begin | |
| ax_d = ax_i; | |
| ax_d.burst = axi_pkg::BURST_INCR; | |
| split_len = 8'd1; | |
| ax_o = ax_d; | |
| ax_o.len = ((wrap_boundary + container_size - ax_i.addr) >> ax_i.size) - 1; | |
| ax_d.len = ((ax_i.addr - wrap_boundary) >> ax_i.size) - 1; | |
| ax_d.addr = wrap_boundary; | |
| ax_valid_o = 1'b1; | |
| if (ax_ready_i) begin | |
| ax_ready_o = 1'b1; | |
| state_d = Busy; | |
| cnt_alloc_req = { AwChan, 1'b1 }; | |
| end | |
| end else begin | |
| ax_o = ax_i; | |
| if (ax_i.burst == axi_pkg::BURST_WRAP) begin | |
| ax_o.burst = axi_pkg::BURST_INCR; | |
| end | |
| ax_valid_o = 1'b1; | |
| if (ax_ready_i) begin | |
| cnt_alloc_req = { AwChan, 1'b1 }; | |
| ax_ready_o = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| Busy: begin | |
| ax_o = ax_q; | |
| ax_valid_o = 1'b1; | |
| if (ax_ready_i) begin | |
| state_d = Idle; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| ax_q <= ('0); | |
| end else begin | |
| ax_q <= (ax_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| state_q <= (Idle); | |
| end else begin | |
| state_q <= (state_d); | |
| end | |
| end | |
| endmodule | |
| module axi_burst_counters #( | |
| parameter int unsigned MaxTxns = 0, | |
| parameter int unsigned IdWidth = 0, | |
| parameter type id_t = logic [IdWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input id_t alloc_id_i, | |
| input axi_pkg::len_t alloc_len_i, | |
| input logic alloc_req_i, | |
| output logic alloc_gnt_o, | |
| input id_t cnt_id_i, | |
| output axi_pkg::len_t cnt_len_o, | |
| input logic cnt_set_err_i, | |
| output logic cnt_err_o, | |
| input logic cnt_dec_i, | |
| input logic cnt_req_i, | |
| output logic cnt_gnt_o | |
| ); | |
| localparam int unsigned CntIdxWidth = (MaxTxns > 1) ? $clog2(MaxTxns) : 32'd1; | |
| typedef logic [CntIdxWidth-1:0] cnt_idx_t; | |
| typedef logic [$bits(axi_pkg::len_t):0] cnt_t; | |
| logic [MaxTxns-1:0] cnt_dec, cnt_free, cnt_set, err_d, err_q; | |
| cnt_t cnt_inp; | |
| cnt_t [MaxTxns-1:0] cnt_oup; | |
| cnt_idx_t cnt_free_idx, cnt_r_idx; | |
| for (genvar i = 0; i < MaxTxns; i++) begin : gen_cnt | |
| counter #( | |
| .WIDTH ( $bits(cnt_t) ) | |
| ) i_cnt ( | |
| .clk_i, | |
| .rst_ni, | |
| .clear_i ( 1'b0 ), | |
| .en_i ( cnt_dec[i] ), | |
| .load_i ( cnt_set[i] ), | |
| .down_i ( 1'b1 ), | |
| .d_i ( cnt_inp ), | |
| .q_o ( cnt_oup[i] ), | |
| .overflow_o ( ) | |
| ); | |
| assign cnt_free[i] = (cnt_oup[i] == '0); | |
| end | |
| assign cnt_inp = {1'b0, alloc_len_i} + 1; | |
| lzc #( | |
| .WIDTH ( MaxTxns ), | |
| .MODE ( 1'b0 ) | |
| ) i_lzc ( | |
| .in_i ( cnt_free ), | |
| .cnt_o ( cnt_free_idx ), | |
| .empty_o ( ) | |
| ); | |
| logic idq_inp_req, idq_inp_gnt, | |
| idq_oup_gnt, idq_oup_valid, idq_oup_pop; | |
| id_queue #( | |
| .ID_WIDTH ( $bits(id_t) ), | |
| .CAPACITY ( MaxTxns ), | |
| .data_t ( cnt_idx_t ) | |
| ) i_idq ( | |
| .clk_i, | |
| .rst_ni, | |
| .inp_id_i ( alloc_id_i ), | |
| .inp_data_i ( cnt_free_idx ), | |
| .inp_req_i ( idq_inp_req ), | |
| .inp_gnt_o ( idq_inp_gnt ), | |
| .exists_data_i ( '0 ), | |
| .exists_mask_i ( '0 ), | |
| .exists_req_i ( 1'b0 ), | |
| .exists_o ( ), | |
| .exists_gnt_o ( ), | |
| .oup_id_i ( cnt_id_i ), | |
| .oup_pop_i ( idq_oup_pop ), | |
| .oup_req_i ( cnt_req_i ), | |
| .oup_data_o ( cnt_r_idx ), | |
| .oup_data_valid_o ( idq_oup_valid ), | |
| .oup_gnt_o ( idq_oup_gnt ), | |
| .full_o ( ), | |
| .empty_o ( ) | |
| ); | |
| assign idq_inp_req = alloc_req_i & alloc_gnt_o; | |
| assign alloc_gnt_o = idq_inp_gnt & |(cnt_free); | |
| assign cnt_gnt_o = idq_oup_gnt & idq_oup_valid; | |
| logic [8:0] read_len; | |
| assign read_len = cnt_oup[cnt_r_idx] - 1; | |
| assign cnt_len_o = read_len[7:0]; | |
| assign idq_oup_pop = cnt_req_i & cnt_gnt_o & cnt_dec_i & (cnt_len_o == 8'd0); | |
| always_comb begin | |
| cnt_dec = '0; | |
| cnt_dec[cnt_r_idx] = cnt_req_i & cnt_gnt_o & cnt_dec_i; | |
| end | |
| always_comb begin | |
| cnt_set = '0; | |
| cnt_set[cnt_free_idx] = alloc_req_i & alloc_gnt_o; | |
| end | |
| always_comb begin | |
| err_d = err_q; | |
| cnt_err_o = err_q[cnt_r_idx]; | |
| if (cnt_req_i && cnt_gnt_o && cnt_set_err_i) begin | |
| err_d[cnt_r_idx] = 1'b1; | |
| cnt_err_o = 1'b1; | |
| end | |
| if (alloc_req_i && alloc_gnt_o) begin | |
| err_d[cnt_free_idx] = 1'b0; | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| err_q <= ('0); | |
| end else begin | |
| err_q <= (err_d); | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_bus_compare #( | |
| parameter int unsigned AxiIdWidth = 32'd0, | |
| parameter int unsigned FifoDepth = 32'd0, | |
| parameter bit UseSize = 1'b0, | |
| parameter int unsigned DataWidth = 32'd8, | |
| parameter type axi_aw_chan_t = logic, | |
| parameter type axi_w_chan_t = logic, | |
| parameter type axi_b_chan_t = logic, | |
| parameter type axi_ar_chan_t = logic, | |
| parameter type axi_r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_rsp_t = logic, | |
| parameter type id_t = logic [2**AxiIdWidth-1:0] | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic testmode_i, | |
| input axi_req_t axi_a_req_i, | |
| output axi_rsp_t axi_a_rsp_o, | |
| output axi_req_t axi_a_req_o, | |
| input axi_rsp_t axi_a_rsp_i, | |
| input axi_req_t axi_b_req_i, | |
| output axi_rsp_t axi_b_rsp_o, | |
| output axi_req_t axi_b_req_o, | |
| input axi_rsp_t axi_b_rsp_i, | |
| output id_t aw_mismatch_o, | |
| output logic w_mismatch_o, | |
| output id_t b_mismatch_o, | |
| output id_t ar_mismatch_o, | |
| output id_t r_mismatch_o, | |
| output logic mismatch_o, | |
| output logic busy_o | |
| ); | |
| assign axi_a_req_o.aw.id = axi_a_req_i.aw.id; | |
| assign axi_a_req_o.aw.addr = axi_a_req_i.aw.addr; | |
| assign axi_a_req_o.aw.len = axi_a_req_i.aw.len; | |
| assign axi_a_req_o.aw.size = axi_a_req_i.aw.size; | |
| assign axi_a_req_o.aw.burst = axi_a_req_i.aw.burst; | |
| assign axi_a_req_o.aw.lock = axi_a_req_i.aw.lock; | |
| assign axi_a_req_o.aw.cache = axi_a_req_i.aw.cache; | |
| assign axi_a_req_o.aw.prot = axi_a_req_i.aw.prot; | |
| assign axi_a_req_o.aw.qos = axi_a_req_i.aw.qos; | |
| assign axi_a_req_o.aw.region = axi_a_req_i.aw.region; | |
| assign axi_a_req_o.aw.atop = axi_a_req_i.aw.atop; | |
| assign axi_a_req_o.aw.user = axi_a_req_i.aw.user; | |
| assign axi_a_req_o.w.data = axi_a_req_i.w.data; | |
| assign axi_a_req_o.w.strb = axi_a_req_i.w.strb; | |
| assign axi_a_req_o.w.last = axi_a_req_i.w.last; | |
| assign axi_a_req_o.w.user = axi_a_req_i.w.user; | |
| assign axi_a_req_o.ar.id = axi_a_req_i.ar.id; | |
| assign axi_a_req_o.ar.addr = axi_a_req_i.ar.addr; | |
| assign axi_a_req_o.ar.len = axi_a_req_i.ar.len; | |
| assign axi_a_req_o.ar.size = axi_a_req_i.ar.size; | |
| assign axi_a_req_o.ar.burst = axi_a_req_i.ar.burst; | |
| assign axi_a_req_o.ar.lock = axi_a_req_i.ar.lock; | |
| assign axi_a_req_o.ar.cache = axi_a_req_i.ar.cache; | |
| assign axi_a_req_o.ar.prot = axi_a_req_i.ar.prot; | |
| assign axi_a_req_o.ar.qos = axi_a_req_i.ar.qos; | |
| assign axi_a_req_o.ar.region = axi_a_req_i.ar.region; | |
| assign axi_a_req_o.ar.user = axi_a_req_i.ar.user; | |
| assign axi_a_rsp_o.r.id = axi_a_rsp_i.r.id; | |
| assign axi_a_rsp_o.r.data = axi_a_rsp_i.r.data; | |
| assign axi_a_rsp_o.r.resp = axi_a_rsp_i.r.resp; | |
| assign axi_a_rsp_o.r.last = axi_a_rsp_i.r.last; | |
| assign axi_a_rsp_o.r.user = axi_a_rsp_i.r.user; | |
| assign axi_a_rsp_o.b.id = axi_a_rsp_i.b.id; | |
| assign axi_a_rsp_o.b.resp = axi_a_rsp_i.b.resp; | |
| assign axi_a_rsp_o.b.user = axi_a_rsp_i.b.user; | |
| assign axi_b_req_o.aw.id = axi_b_req_i.aw.id; | |
| assign axi_b_req_o.aw.addr = axi_b_req_i.aw.addr; | |
| assign axi_b_req_o.aw.len = axi_b_req_i.aw.len; | |
| assign axi_b_req_o.aw.size = axi_b_req_i.aw.size; | |
| assign axi_b_req_o.aw.burst = axi_b_req_i.aw.burst; | |
| assign axi_b_req_o.aw.lock = axi_b_req_i.aw.lock; | |
| assign axi_b_req_o.aw.cache = axi_b_req_i.aw.cache; | |
| assign axi_b_req_o.aw.prot = axi_b_req_i.aw.prot; | |
| assign axi_b_req_o.aw.qos = axi_b_req_i.aw.qos; | |
| assign axi_b_req_o.aw.region = axi_b_req_i.aw.region; | |
| assign axi_b_req_o.aw.atop = axi_b_req_i.aw.atop; | |
| assign axi_b_req_o.aw.user = axi_b_req_i.aw.user; | |
| assign axi_b_req_o.w.data = axi_b_req_i.w.data; | |
| assign axi_b_req_o.w.strb = axi_b_req_i.w.strb; | |
| assign axi_b_req_o.w.last = axi_b_req_i.w.last; | |
| assign axi_b_req_o.w.user = axi_b_req_i.w.user; | |
| assign axi_b_req_o.ar.id = axi_b_req_i.ar.id; | |
| assign axi_b_req_o.ar.addr = axi_b_req_i.ar.addr; | |
| assign axi_b_req_o.ar.len = axi_b_req_i.ar.len; | |
| assign axi_b_req_o.ar.size = axi_b_req_i.ar.size; | |
| assign axi_b_req_o.ar.burst = axi_b_req_i.ar.burst; | |
| assign axi_b_req_o.ar.lock = axi_b_req_i.ar.lock; | |
| assign axi_b_req_o.ar.cache = axi_b_req_i.ar.cache; | |
| assign axi_b_req_o.ar.prot = axi_b_req_i.ar.prot; | |
| assign axi_b_req_o.ar.qos = axi_b_req_i.ar.qos; | |
| assign axi_b_req_o.ar.region = axi_b_req_i.ar.region; | |
| assign axi_b_req_o.ar.user = axi_b_req_i.ar.user; | |
| assign axi_b_rsp_o.r.id = axi_b_rsp_i.r.id; | |
| assign axi_b_rsp_o.r.data = axi_b_rsp_i.r.data; | |
| assign axi_b_rsp_o.r.resp = axi_b_rsp_i.r.resp; | |
| assign axi_b_rsp_o.r.last = axi_b_rsp_i.r.last; | |
| assign axi_b_rsp_o.r.user = axi_b_rsp_i.r.user; | |
| assign axi_b_rsp_o.b.id = axi_b_rsp_i.b.id; | |
| assign axi_b_rsp_o.b.resp = axi_b_rsp_i.b.resp; | |
| assign axi_b_rsp_o.b.user = axi_b_rsp_i.b.user; | |
| id_t fifo_valid_aw_a, fifo_ready_aw_a; | |
| id_t fifo_valid_b_a, fifo_ready_b_a; | |
| id_t fifo_valid_ar_a, fifo_ready_ar_a; | |
| id_t fifo_valid_r_a, fifo_ready_r_a; | |
| logic fifo_sel_valid_aw_a, fifo_sel_ready_aw_a; | |
| logic fifo_sel_valid_w_a, fifo_sel_ready_w_a; | |
| logic fifo_sel_valid_b_a, fifo_sel_ready_b_a; | |
| logic fifo_sel_valid_ar_a, fifo_sel_ready_ar_a; | |
| logic fifo_sel_valid_r_a, fifo_sel_ready_r_a; | |
| id_t fifo_valid_aw_b, fifo_ready_aw_b; | |
| id_t fifo_valid_b_b, fifo_ready_b_b; | |
| id_t fifo_valid_ar_b, fifo_ready_ar_b; | |
| id_t fifo_valid_r_b, fifo_ready_r_b; | |
| logic fifo_sel_valid_aw_b, fifo_sel_ready_aw_b; | |
| logic fifo_sel_valid_w_b, fifo_sel_ready_w_b; | |
| logic fifo_sel_valid_b_b, fifo_sel_ready_b_b; | |
| logic fifo_sel_valid_ar_b, fifo_sel_ready_ar_b; | |
| logic fifo_sel_valid_r_b, fifo_sel_ready_r_b; | |
| id_t fifo_cmp_valid_aw_a; | |
| logic fifo_cmp_valid_w_a; | |
| id_t fifo_cmp_valid_b_a; | |
| id_t fifo_cmp_valid_ar_a; | |
| id_t fifo_cmp_valid_r_a; | |
| id_t fifo_cmp_valid_aw_b; | |
| logic fifo_cmp_valid_w_b; | |
| id_t fifo_cmp_valid_b_b; | |
| id_t fifo_cmp_valid_ar_b; | |
| id_t fifo_cmp_valid_r_b; | |
| axi_aw_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_aw_a; | |
| axi_w_chan_t fifo_cmp_data_w_a; | |
| axi_b_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_b_a; | |
| axi_ar_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_ar_a; | |
| axi_r_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_r_a; | |
| axi_aw_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_aw_b; | |
| axi_w_chan_t fifo_cmp_data_w_b; | |
| axi_b_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_b_b; | |
| axi_ar_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_ar_b; | |
| axi_r_chan_t [2**AxiIdWidth-1:0] fifo_cmp_data_r_b; | |
| logic [2:0] w_size; | |
| logic [$clog2(DataWidth/8)-1:0] w_lower, w_offset, w_increment; | |
| logic [2**AxiIdWidth-1:0][2:0] r_size; | |
| logic [2**AxiIdWidth-1:0][$clog2(DataWidth/8)-1:0] r_lower, r_offset, r_increment; | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_aw_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_a_req_i.aw_valid ), | |
| .ready_o ( axi_a_rsp_o.aw_ready ), | |
| .valid_o ( {fifo_sel_valid_aw_a, axi_a_req_o.aw_valid} ), | |
| .ready_i ( {fifo_sel_ready_aw_a, axi_a_rsp_i.aw_ready} ) | |
| ); | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_w_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_a_req_i.w_valid ), | |
| .ready_o ( axi_a_rsp_o.w_ready ), | |
| .valid_o ( {fifo_sel_valid_w_a, axi_a_req_o.w_valid} ), | |
| .ready_i ( {fifo_sel_ready_w_a, axi_a_rsp_i.w_ready} ) | |
| ); | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_b_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_a_rsp_i.b_valid ), | |
| .ready_o ( axi_a_req_o.b_ready ), | |
| .valid_o ( {fifo_sel_valid_b_a, axi_a_rsp_o.b_valid} ), | |
| .ready_i ( {fifo_sel_ready_b_a, axi_a_req_i.b_ready} ) | |
| ); | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_ar_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_a_req_i.ar_valid ), | |
| .ready_o ( axi_a_rsp_o.ar_ready ), | |
| .valid_o ( {fifo_sel_valid_ar_a, axi_a_req_o.ar_valid} ), | |
| .ready_i ( {fifo_sel_ready_ar_a, axi_a_rsp_i.ar_ready} ) | |
| ); | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_r_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_a_rsp_i.r_valid ), | |
| .ready_o ( axi_a_req_o.r_ready ), | |
| .valid_o ( {fifo_sel_valid_r_a, axi_a_rsp_o.r_valid} ), | |
| .ready_i ( {fifo_sel_ready_r_a, axi_a_req_i.r_ready} ) | |
| ); | |
| for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_fifos_a | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_aw_chan_t ) | |
| ) i_stream_fifo_aw_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_a_req_i.aw ), | |
| .valid_i ( fifo_valid_aw_a [id] ), | |
| .ready_o ( fifo_ready_aw_a [id] ), | |
| .data_o ( fifo_cmp_data_aw_a [id] ), | |
| .valid_o ( fifo_cmp_valid_aw_a [id] ), | |
| .ready_i ( fifo_cmp_valid_aw_a [id] & fifo_cmp_valid_aw_b [id] ) | |
| ); | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_b_chan_t ) | |
| ) i_stream_fifo_b_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_a_rsp_i.b ), | |
| .valid_i ( fifo_valid_b_a [id] ), | |
| .ready_o ( fifo_ready_b_a [id] ), | |
| .data_o ( fifo_cmp_data_b_a [id] ), | |
| .valid_o ( fifo_cmp_valid_b_a [id] ), | |
| .ready_i ( fifo_cmp_valid_b_a [id] & fifo_cmp_valid_b_b [id] ) | |
| ); | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_ar_chan_t ) | |
| ) i_stream_fifo_ar_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_a_req_i.ar ), | |
| .valid_i ( fifo_valid_ar_a [id] ), | |
| .ready_o ( fifo_ready_ar_a [id] ), | |
| .data_o ( fifo_cmp_data_ar_a [id] ), | |
| .valid_o ( fifo_cmp_valid_ar_a [id] ), | |
| .ready_i ( fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id] ) | |
| ); | |
| if (UseSize) begin : gen_r_size | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), | |
| .DEPTH ( 2*FifoDepth ) | |
| ) i_stream_fifo_w_size ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o (), | |
| .data_i ( {axi_a_req_i.ar.addr[$clog2(DataWidth/8)-1:0], axi_a_req_i.ar.size} ), | |
| .valid_i ( fifo_valid_ar_a [id] & fifo_ready_ar_a [id] ), | |
| .ready_o (), | |
| .data_o ( {r_offset[id], r_size[id]} ), | |
| .valid_o (), | |
| .ready_i ( fifo_cmp_valid_r_a[id] & fifo_cmp_valid_r_b[id] & fifo_cmp_data_r_a[id].last ) | |
| ); | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : proc_r_increment | |
| if(!rst_ni) begin | |
| r_increment[id] <= '0; | |
| end else begin | |
| if (fifo_cmp_valid_r_a[id] && fifo_cmp_valid_r_b[id]) begin | |
| if (fifo_cmp_data_r_a[id].last) begin | |
| r_increment[id] <= '0; | |
| end else begin | |
| r_increment[id] <= r_increment[id] + 2**r_size[id] - ((r_offset[id]+r_increment[id])%(2**r_size[id])); | |
| end | |
| end | |
| end | |
| end | |
| assign r_lower[id] = r_offset[id] + r_increment[id]; | |
| end else begin : gen_no_size | |
| assign r_offset[id] = '0; | |
| assign r_size[id] = '1; | |
| assign r_lower[id] = '0; | |
| end | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_r_chan_t ) | |
| ) i_stream_fifo_r_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_a_rsp_i.r ), | |
| .valid_i ( fifo_valid_r_a [id] ), | |
| .ready_o ( fifo_ready_r_a [id] ), | |
| .data_o ( fifo_cmp_data_r_a [id] ), | |
| .valid_o ( fifo_cmp_valid_r_a [id] ), | |
| .ready_i ( fifo_cmp_valid_r_a [id] & fifo_cmp_valid_r_b [id] ) | |
| ); | |
| end | |
| if (UseSize) begin : gen_w_size | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( $clog2(DataWidth/8)+3 ), | |
| .DEPTH ( FifoDepth ) | |
| ) i_stream_fifo_w_size ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o (), | |
| .data_i ( {axi_a_req_i.aw.addr[$clog2(DataWidth/8)-1:0], axi_a_req_i.aw.size} ), | |
| .valid_i ( axi_a_req_i.aw_valid & axi_a_rsp_o.aw_ready ), | |
| .ready_o (), | |
| .data_o ( {w_offset, w_size} ), | |
| .valid_o (), | |
| .ready_i ( fifo_cmp_valid_w_a & fifo_cmp_valid_w_b & fifo_cmp_data_w_a.last ) | |
| ); | |
| always_ff @(posedge clk_i or negedge rst_ni) begin : proc_w_increment | |
| if(!rst_ni) begin | |
| w_increment <= '0; | |
| end else begin | |
| if (fifo_cmp_valid_w_a && fifo_cmp_valid_w_b) begin | |
| if (fifo_cmp_data_w_a.last) begin | |
| w_increment <= '0; | |
| end else begin | |
| w_increment <= (w_increment + 2**w_size) - ((w_offset+w_increment)%(2**w_size)); | |
| end | |
| end | |
| end | |
| end | |
| assign w_lower = w_offset + w_increment; | |
| end else begin : gen_no_size | |
| assign w_offset = '0; | |
| assign w_size = '1; | |
| assign w_lower = '0; | |
| end | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_w_chan_t ) | |
| ) i_stream_fifo_w_a ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_a_req_i.w ), | |
| .valid_i ( fifo_sel_valid_w_a ), | |
| .ready_o ( fifo_sel_ready_w_a ), | |
| .data_o ( fifo_cmp_data_w_a ), | |
| .valid_o ( fifo_cmp_valid_w_a ), | |
| .ready_i ( fifo_cmp_valid_w_a & fifo_cmp_valid_w_b ) | |
| ); | |
| always_comb begin : gen_handshaking_a | |
| fifo_valid_aw_a = '0; | |
| fifo_sel_ready_aw_a = '0; | |
| fifo_valid_aw_a [axi_a_req_i.aw.id] = fifo_sel_valid_aw_a; | |
| fifo_sel_ready_aw_a = fifo_ready_aw_a[axi_a_req_i.aw.id]; | |
| fifo_valid_b_a = '0; | |
| fifo_sel_ready_b_a = '0; | |
| fifo_valid_b_a [axi_a_rsp_i.b.id] = fifo_sel_valid_b_a; | |
| fifo_sel_ready_b_a = fifo_ready_b_a[axi_a_rsp_i.b.id]; | |
| fifo_valid_ar_a = '0; | |
| fifo_sel_ready_ar_a = '0; | |
| fifo_valid_ar_a [axi_a_req_i.ar.id] = fifo_sel_valid_ar_a; | |
| fifo_sel_ready_ar_a = fifo_ready_ar_a[axi_a_req_i.ar.id]; | |
| fifo_valid_r_a = '0; | |
| fifo_sel_ready_r_a = '0; | |
| fifo_valid_r_a [axi_a_rsp_i.r.id] = fifo_sel_valid_r_a; | |
| fifo_sel_ready_r_a = fifo_ready_r_a[axi_a_rsp_i.r.id]; | |
| end | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_aw_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_b_req_i.aw_valid ), | |
| .ready_o ( axi_b_rsp_o.aw_ready ), | |
| .valid_o ( {fifo_sel_valid_aw_b, axi_b_req_o.aw_valid} ), | |
| .ready_i ( {fifo_sel_ready_aw_b, axi_b_rsp_i.aw_ready} ) | |
| ); | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_w_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_b_req_i.w_valid ), | |
| .ready_o ( axi_b_rsp_o.w_ready ), | |
| .valid_o ( {fifo_sel_valid_w_b, axi_b_req_o.w_valid} ), | |
| .ready_i ( {fifo_sel_ready_w_b, axi_b_rsp_i.w_ready} ) | |
| ); | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_b_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_b_rsp_i.b_valid ), | |
| .ready_o ( axi_b_req_o.b_ready ), | |
| .valid_o ( {fifo_sel_valid_b_b, axi_b_rsp_o.b_valid} ), | |
| .ready_i ( {fifo_sel_ready_b_b, axi_b_req_i.b_ready} ) | |
| ); | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_ar_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_b_req_i.ar_valid ), | |
| .ready_o ( axi_b_rsp_o.ar_ready ), | |
| .valid_o ( {fifo_sel_valid_ar_b, axi_b_req_o.ar_valid} ), | |
| .ready_i ( {fifo_sel_ready_ar_b, axi_b_rsp_i.ar_ready} ) | |
| ); | |
| stream_fork #( | |
| .N_OUP ( 32'd2 ) | |
| ) i_stream_fork_r_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( axi_b_rsp_i.r_valid ), | |
| .ready_o ( axi_b_req_o.r_ready ), | |
| .valid_o ( {fifo_sel_valid_r_b, axi_b_rsp_o.r_valid} ), | |
| .ready_i ( {fifo_sel_ready_r_b, axi_b_req_i.r_ready} ) | |
| ); | |
| for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_fifos_b | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_aw_chan_t ) | |
| ) i_stream_fifo_aw_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_b_req_i.aw ), | |
| .valid_i ( fifo_valid_aw_b [id] ), | |
| .ready_o ( fifo_ready_aw_b [id] ), | |
| .data_o ( fifo_cmp_data_aw_b [id] ), | |
| .valid_o ( fifo_cmp_valid_aw_b [id] ), | |
| .ready_i ( fifo_cmp_valid_aw_a [id] & fifo_cmp_valid_aw_b [id] ) | |
| ); | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_b_chan_t ) | |
| ) i_stream_fifo_b_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_b_rsp_i.b ), | |
| .valid_i ( fifo_valid_b_b [id] ), | |
| .ready_o ( fifo_ready_b_b [id] ), | |
| .data_o ( fifo_cmp_data_b_b [id] ), | |
| .valid_o ( fifo_cmp_valid_b_b [id] ), | |
| .ready_i ( fifo_cmp_valid_b_a [id] & fifo_cmp_valid_b_b [id] ) | |
| ); | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_ar_chan_t ) | |
| ) i_stream_fifo_ar_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_b_req_i.ar ), | |
| .valid_i ( fifo_valid_ar_b [id] ), | |
| .ready_o ( fifo_ready_ar_b [id] ), | |
| .data_o ( fifo_cmp_data_ar_b [id] ), | |
| .valid_o ( fifo_cmp_valid_ar_b [id] ), | |
| .ready_i ( fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id] ) | |
| ); | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_r_chan_t ) | |
| ) i_stream_fifo_r_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_b_rsp_i.r ), | |
| .valid_i ( fifo_valid_r_b [id] ), | |
| .ready_o ( fifo_ready_r_b [id] ), | |
| .data_o ( fifo_cmp_data_r_b [id] ), | |
| .valid_o ( fifo_cmp_valid_r_b [id] ), | |
| .ready_i ( fifo_cmp_valid_r_a [id] & fifo_cmp_valid_r_b [id] ) | |
| ); | |
| end | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 1'b0 ), | |
| .DEPTH ( FifoDepth ), | |
| .T ( axi_w_chan_t ) | |
| ) i_stream_fifo_w_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( axi_b_req_i.w ), | |
| .valid_i ( fifo_sel_valid_w_b ), | |
| .ready_o ( fifo_sel_ready_w_b ), | |
| .data_o ( fifo_cmp_data_w_b ), | |
| .valid_o ( fifo_cmp_valid_w_b ), | |
| .ready_i ( fifo_cmp_valid_w_a & fifo_cmp_valid_w_b ) | |
| ); | |
| always_comb begin : gen_handshaking_b | |
| fifo_valid_aw_b = '0; | |
| fifo_sel_ready_aw_b = '0; | |
| fifo_valid_aw_b [axi_b_req_i.aw.id] = fifo_sel_valid_aw_b; | |
| fifo_sel_ready_aw_b = fifo_ready_aw_b[axi_b_req_i.aw.id]; | |
| fifo_valid_b_b = '0; | |
| fifo_sel_ready_b_b = '0; | |
| fifo_valid_b_b [axi_b_rsp_i.b.id] = fifo_sel_valid_b_b; | |
| fifo_sel_ready_b_b = fifo_ready_b_b[axi_b_rsp_i.b.id]; | |
| fifo_valid_ar_b = '0; | |
| fifo_sel_ready_ar_b = '0; | |
| fifo_valid_ar_b [axi_b_req_i.ar.id] = fifo_sel_valid_ar_b; | |
| fifo_sel_ready_ar_b = fifo_ready_ar_b[axi_b_req_i.ar.id]; | |
| fifo_valid_r_b = '0; | |
| fifo_sel_ready_r_b = '0; | |
| fifo_valid_r_b [axi_b_rsp_i.r.id] = fifo_sel_valid_r_b; | |
| fifo_sel_ready_r_b = fifo_ready_r_b[axi_b_rsp_i.r.id]; | |
| end | |
| for (genvar id = 0; id < 2**AxiIdWidth; id++) begin : gen_cmp | |
| logic [DataWidth/8-1:0] r_data_partial_mismatch; | |
| logic r_data_mismatch; | |
| if (UseSize) begin : gen_r_mismatch_sized | |
| for (genvar j = 0; j < DataWidth/8; j++) begin : gen_r_partial_mismatch | |
| assign r_data_partial_mismatch[j] = fifo_cmp_data_r_a[id].data[8*j+:8] != fifo_cmp_data_r_b[id].data[8*j+:8]; | |
| end | |
| always_comb begin : proc_r_data_mismatch | |
| r_data_mismatch = '0; | |
| for (int unsigned j = 0; j < DataWidth/8; j++) begin | |
| if (j >= r_lower[id] && j < (r_lower[id] + 2**r_size[id])-((r_lower[id] + 2**r_size[id])%(2**r_size[id])) ) begin | |
| r_data_mismatch |= r_data_partial_mismatch[j]; | |
| end | |
| end | |
| end | |
| end else begin : gen_r_mismatch_unsized | |
| assign r_data_mismatch = fifo_cmp_data_r_a[id].data != fifo_cmp_data_r_b[id].data; | |
| end | |
| assign aw_mismatch_o [id] = (fifo_cmp_valid_aw_a [id] & fifo_cmp_valid_aw_b [id]) ? | |
| fifo_cmp_data_aw_a [id] != fifo_cmp_data_aw_b [id] : '0; | |
| assign b_mismatch_o [id] = (fifo_cmp_valid_b_a [id] & fifo_cmp_valid_b_b [id]) ? | |
| fifo_cmp_data_b_a [id] != fifo_cmp_data_b_b [id] : '0; | |
| assign ar_mismatch_o [id] = (fifo_cmp_valid_ar_a [id] & fifo_cmp_valid_ar_b [id]) ? | |
| fifo_cmp_data_ar_a [id] != fifo_cmp_data_ar_b [id] : '0; | |
| assign r_mismatch_o [id] = (fifo_cmp_valid_r_a [id] & fifo_cmp_valid_r_b [id]) ? | |
| ( fifo_cmp_data_r_a[id].id != fifo_cmp_data_r_b[id].id | | |
| r_data_mismatch | | |
| fifo_cmp_data_r_a[id].resp != fifo_cmp_data_r_b[id].resp | | |
| fifo_cmp_data_r_a[id].last != fifo_cmp_data_r_b[id].last | | |
| fifo_cmp_data_r_a[id].user != fifo_cmp_data_r_b[id].user ) | |
| : '0; | |
| end | |
| logic [DataWidth/8-1:0] w_data_partial_mismatch; | |
| logic w_data_mismatch; | |
| if (UseSize) begin : gen_w_mismatch_sized | |
| for (genvar j = 0; j < DataWidth/8; j++) begin : gen_w_partial_mismatch | |
| assign w_data_partial_mismatch[j] = fifo_cmp_data_w_a.data[8*j+:8] != fifo_cmp_data_w_b.data[8*j+:8] | | |
| fifo_cmp_data_w_a.strb[ j ] != fifo_cmp_data_w_b.strb[ j ]; | |
| end | |
| always_comb begin : proc_w_data_mismatch | |
| w_data_mismatch = '0; | |
| for (int unsigned j = 0; j < DataWidth/8; j++) begin | |
| if (j >= w_lower && j < (w_lower + 2**w_size)-((w_lower + 2**w_size)%(2**w_size)) ) begin | |
| w_data_mismatch |= w_data_partial_mismatch[j]; | |
| end | |
| end | |
| end | |
| end else begin : gen_w_mismatch_unsized | |
| assign w_data_mismatch = fifo_cmp_data_w_a.data != fifo_cmp_data_w_b.data | | |
| fifo_cmp_data_w_a.strb != fifo_cmp_data_w_b.strb; | |
| end | |
| assign w_mismatch_o = (fifo_cmp_valid_w_a & fifo_cmp_valid_w_b ) ? | |
| ( w_data_mismatch | | |
| fifo_cmp_data_w_a.last != fifo_cmp_data_w_b.last | | |
| fifo_cmp_data_w_a.user != fifo_cmp_data_w_b.user ) | |
| : '0; | |
| assign busy_o = (|fifo_cmp_valid_aw_a) | (|fifo_cmp_valid_aw_b) | | |
| (|fifo_cmp_valid_w_a) | (|fifo_cmp_valid_w_b) | | |
| (|fifo_cmp_valid_b_a) | (|fifo_cmp_valid_b_b) | | |
| (|fifo_cmp_valid_ar_a) | (|fifo_cmp_valid_ar_b) | | |
| (|fifo_cmp_valid_r_a) | (|fifo_cmp_valid_r_b); | |
| assign mismatch_o = (|aw_mismatch_o) | (|w_mismatch_o) | (|b_mismatch_o) | | |
| (|ar_mismatch_o) | (|r_mismatch_o); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_cdc_dst #( | |
| parameter int unsigned LogDepth = 1, | |
| parameter int unsigned SyncStages = 2, | |
| parameter type aw_chan_t = logic, | |
| parameter type w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input aw_chan_t [2**LogDepth-1:0] async_data_slave_aw_data_i, | |
| input logic [LogDepth:0] async_data_slave_aw_wptr_i, | |
| output logic [LogDepth:0] async_data_slave_aw_rptr_o, | |
| input w_chan_t [2**LogDepth-1:0] async_data_slave_w_data_i, | |
| input logic [LogDepth:0] async_data_slave_w_wptr_i, | |
| output logic [LogDepth:0] async_data_slave_w_rptr_o, | |
| output b_chan_t [2**LogDepth-1:0] async_data_slave_b_data_o, | |
| output logic [LogDepth:0] async_data_slave_b_wptr_o, | |
| input logic [LogDepth:0] async_data_slave_b_rptr_i, | |
| input ar_chan_t [2**LogDepth-1:0] async_data_slave_ar_data_i, | |
| input logic [LogDepth:0] async_data_slave_ar_wptr_i, | |
| output logic [LogDepth:0] async_data_slave_ar_rptr_o, | |
| output r_chan_t [2**LogDepth-1:0] async_data_slave_r_data_o, | |
| output logic [LogDepth:0] async_data_slave_r_wptr_o, | |
| input logic [LogDepth:0] async_data_slave_r_rptr_i, | |
| input logic dst_clk_i, | |
| input logic dst_rst_ni, | |
| output axi_req_t dst_req_o, | |
| input axi_resp_t dst_resp_i | |
| ); | |
| cdc_fifo_gray_dst #( | |
| .T ( aw_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_dst_aw ( | |
| .async_data_i ( async_data_slave_aw_data_i ), | |
| .async_wptr_i ( async_data_slave_aw_wptr_i ), | |
| .async_rptr_o ( async_data_slave_aw_rptr_o ), | |
| .dst_clk_i, | |
| .dst_rst_ni, | |
| .dst_data_o ( dst_req_o.aw ), | |
| .dst_valid_o ( dst_req_o.aw_valid ), | |
| .dst_ready_i ( dst_resp_i.aw_ready ) | |
| ); | |
| cdc_fifo_gray_dst #( | |
| .T ( w_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_dst_w ( | |
| .async_data_i ( async_data_slave_w_data_i ), | |
| .async_wptr_i ( async_data_slave_w_wptr_i ), | |
| .async_rptr_o ( async_data_slave_w_rptr_o ), | |
| .dst_clk_i, | |
| .dst_rst_ni, | |
| .dst_data_o ( dst_req_o.w ), | |
| .dst_valid_o ( dst_req_o.w_valid ), | |
| .dst_ready_i ( dst_resp_i.w_ready ) | |
| ); | |
| cdc_fifo_gray_src #( | |
| .T ( b_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_src_b ( | |
| .src_clk_i ( dst_clk_i ), | |
| .src_rst_ni ( dst_rst_ni ), | |
| .src_data_i ( dst_resp_i.b ), | |
| .src_valid_i ( dst_resp_i.b_valid ), | |
| .src_ready_o ( dst_req_o.b_ready ), | |
| .async_data_o ( async_data_slave_b_data_o ), | |
| .async_wptr_o ( async_data_slave_b_wptr_o ), | |
| .async_rptr_i ( async_data_slave_b_rptr_i ) | |
| ); | |
| cdc_fifo_gray_dst #( | |
| .T ( ar_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_dst_ar ( | |
| .dst_clk_i, | |
| .dst_rst_ni, | |
| .dst_data_o ( dst_req_o.ar ), | |
| .dst_valid_o ( dst_req_o.ar_valid ), | |
| .dst_ready_i ( dst_resp_i.ar_ready ), | |
| .async_data_i ( async_data_slave_ar_data_i ), | |
| .async_wptr_i ( async_data_slave_ar_wptr_i ), | |
| .async_rptr_o ( async_data_slave_ar_rptr_o ) | |
| ); | |
| cdc_fifo_gray_src #( | |
| .T ( r_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_src_r ( | |
| .src_clk_i ( dst_clk_i ), | |
| .src_rst_ni ( dst_rst_ni ), | |
| .src_data_i ( dst_resp_i.r ), | |
| .src_valid_i ( dst_resp_i.r_valid ), | |
| .src_ready_o ( dst_req_o.r_ready ), | |
| .async_data_o ( async_data_slave_r_data_o ), | |
| .async_wptr_o ( async_data_slave_r_wptr_o ), | |
| .async_rptr_i ( async_data_slave_r_rptr_i ) | |
| ); | |
| endmodule | |
| module axi_cdc_dst_intf #( | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0, | |
| parameter int unsigned LOG_DEPTH = 1, | |
| parameter int unsigned SYNC_STAGES = 2 | |
| ) ( | |
| AXI_BUS_ASYNC_GRAY.Slave src, | |
| input logic dst_clk_i, | |
| input logic dst_rst_ni, | |
| AXI_BUS.Master dst | |
| ); | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| b_chan_t b; | |
| logic r_valid; | |
| r_chan_t r; | |
| } resp_t; | |
| req_t dst_req; | |
| resp_t dst_resp; | |
| axi_cdc_dst #( | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( req_t ), | |
| .axi_resp_t ( resp_t ), | |
| .LogDepth ( LOG_DEPTH ), | |
| .SyncStages ( SYNC_STAGES ) | |
| ) i_axi_cdc_dst ( | |
| .async_data_slave_aw_data_i ( src.aw_data ), | |
| .async_data_slave_aw_wptr_i ( src.aw_wptr ), | |
| .async_data_slave_aw_rptr_o ( src.aw_rptr ), | |
| .async_data_slave_w_data_i ( src.w_data ), | |
| .async_data_slave_w_wptr_i ( src.w_wptr ), | |
| .async_data_slave_w_rptr_o ( src.w_rptr ), | |
| .async_data_slave_b_data_o ( src.b_data ), | |
| .async_data_slave_b_wptr_o ( src.b_wptr ), | |
| .async_data_slave_b_rptr_i ( src.b_rptr ), | |
| .async_data_slave_ar_data_i ( src.ar_data ), | |
| .async_data_slave_ar_wptr_i ( src.ar_wptr ), | |
| .async_data_slave_ar_rptr_o ( src.ar_rptr ), | |
| .async_data_slave_r_data_o ( src.r_data ), | |
| .async_data_slave_r_wptr_o ( src.r_wptr ), | |
| .async_data_slave_r_rptr_i ( src.r_rptr ), | |
| .dst_clk_i, | |
| .dst_rst_ni, | |
| .dst_req_o ( dst_req ), | |
| .dst_resp_i ( dst_resp ) | |
| ); | |
| assign dst.aw_id = dst_req.aw.id; | |
| assign dst.aw_addr = dst_req.aw.addr; | |
| assign dst.aw_len = dst_req.aw.len; | |
| assign dst.aw_size = dst_req.aw.size; | |
| assign dst.aw_burst = dst_req.aw.burst; | |
| assign dst.aw_lock = dst_req.aw.lock; | |
| assign dst.aw_cache = dst_req.aw.cache; | |
| assign dst.aw_prot = dst_req.aw.prot; | |
| assign dst.aw_qos = dst_req.aw.qos; | |
| assign dst.aw_region = dst_req.aw.region; | |
| assign dst.aw_atop = dst_req.aw.atop; | |
| assign dst.aw_user = dst_req.aw.user; | |
| assign dst.aw_valid = dst_req.aw_valid; | |
| assign dst.w_data = dst_req.w.data; | |
| assign dst.w_strb = dst_req.w.strb; | |
| assign dst.w_last = dst_req.w.last; | |
| assign dst.w_user = dst_req.w.user; | |
| assign dst.w_valid = dst_req.w_valid; | |
| assign dst.b_ready = dst_req.b_ready; | |
| assign dst.ar_id = dst_req.ar.id; | |
| assign dst.ar_addr = dst_req.ar.addr; | |
| assign dst.ar_len = dst_req.ar.len; | |
| assign dst.ar_size = dst_req.ar.size; | |
| assign dst.ar_burst = dst_req.ar.burst; | |
| assign dst.ar_lock = dst_req.ar.lock; | |
| assign dst.ar_cache = dst_req.ar.cache; | |
| assign dst.ar_prot = dst_req.ar.prot; | |
| assign dst.ar_qos = dst_req.ar.qos; | |
| assign dst.ar_region = dst_req.ar.region; | |
| assign dst.ar_user = dst_req.ar.user; | |
| assign dst.ar_valid = dst_req.ar_valid; | |
| assign dst.r_ready = dst_req.r_ready; | |
| assign dst_resp.aw_ready = dst.aw_ready; | |
| assign dst_resp.ar_ready = dst.ar_ready; | |
| assign dst_resp.w_ready = dst.w_ready; | |
| assign dst_resp.b_valid = dst.b_valid; | |
| assign dst_resp.b.id = dst.b_id; | |
| assign dst_resp.b.resp = dst.b_resp; | |
| assign dst_resp.b.user = dst.b_user; | |
| assign dst_resp.r_valid = dst.r_valid; | |
| assign dst_resp.r.id = dst.r_id; | |
| assign dst_resp.r.data = dst.r_data; | |
| assign dst_resp.r.resp = dst.r_resp; | |
| assign dst_resp.r.last = dst.r_last; | |
| assign dst_resp.r.user = dst.r_user; | |
| endmodule | |
| module axi_lite_cdc_dst_intf #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned LOG_DEPTH = 1, | |
| parameter int unsigned SYNC_STAGES = 2 | |
| ) ( | |
| AXI_LITE_ASYNC_GRAY.Slave src, | |
| input logic dst_clk_i, | |
| input logic dst_rst_ni, | |
| AXI_LITE.Master dst | |
| ); | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_t r; | |
| logic r_valid; | |
| } resp_t; | |
| req_t dst_req; | |
| resp_t dst_resp; | |
| axi_cdc_dst #( | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( req_t ), | |
| .axi_resp_t ( resp_t ), | |
| .LogDepth ( LOG_DEPTH ), | |
| .SyncStages ( SYNC_STAGES ) | |
| ) i_axi_cdc_dst ( | |
| .async_data_slave_aw_data_i ( src.aw_data ), | |
| .async_data_slave_aw_wptr_i ( src.aw_wptr ), | |
| .async_data_slave_aw_rptr_o ( src.aw_rptr ), | |
| .async_data_slave_w_data_i ( src.w_data ), | |
| .async_data_slave_w_wptr_i ( src.w_wptr ), | |
| .async_data_slave_w_rptr_o ( src.w_rptr ), | |
| .async_data_slave_b_data_o ( src.b_data ), | |
| .async_data_slave_b_wptr_o ( src.b_wptr ), | |
| .async_data_slave_b_rptr_i ( src.b_rptr ), | |
| .async_data_slave_ar_data_i ( src.ar_data ), | |
| .async_data_slave_ar_wptr_i ( src.ar_wptr ), | |
| .async_data_slave_ar_rptr_o ( src.ar_rptr ), | |
| .async_data_slave_r_data_o ( src.r_data ), | |
| .async_data_slave_r_wptr_o ( src.r_wptr ), | |
| .async_data_slave_r_rptr_i ( src.r_rptr ), | |
| .dst_clk_i, | |
| .dst_rst_ni, | |
| .dst_req_o ( dst_req ), | |
| .dst_resp_i ( dst_resp ) | |
| ); | |
| assign dst.aw_addr = dst_req.aw.addr; | |
| assign dst.aw_prot = dst_req.aw.prot; | |
| assign dst.aw_valid = dst_req.aw_valid; | |
| assign dst.w_data = dst_req.w.data; | |
| assign dst.w_strb = dst_req.w.strb; | |
| assign dst.w_valid = dst_req.w_valid; | |
| assign dst.b_ready = dst_req.b_ready; | |
| assign dst.ar_addr = dst_req.ar.addr; | |
| assign dst.ar_prot = dst_req.ar.prot; | |
| assign dst.ar_valid = dst_req.ar_valid; | |
| assign dst.r_ready = dst_req.r_ready; | |
| assign dst_resp.aw_ready = dst.aw_ready; | |
| assign dst_resp.ar_ready = dst.ar_ready; | |
| assign dst_resp.w_ready = dst.w_ready; | |
| assign dst_resp.b_valid = dst.b_valid; | |
| assign dst_resp.b.resp = dst.b_resp; | |
| assign dst_resp.r_valid = dst.r_valid; | |
| assign dst_resp.r.data = dst.r_data; | |
| assign dst_resp.r.resp = dst.r_resp; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_cdc_src #( | |
| parameter int unsigned LogDepth = 1, | |
| parameter int unsigned SyncStages = 2, | |
| parameter type aw_chan_t = logic, | |
| parameter type w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input logic src_clk_i, | |
| input logic src_rst_ni, | |
| input axi_req_t src_req_i, | |
| output axi_resp_t src_resp_o, | |
| output aw_chan_t [2**LogDepth-1:0] async_data_master_aw_data_o, | |
| output logic [LogDepth:0] async_data_master_aw_wptr_o, | |
| input logic [LogDepth:0] async_data_master_aw_rptr_i, | |
| output w_chan_t [2**LogDepth-1:0] async_data_master_w_data_o, | |
| output logic [LogDepth:0] async_data_master_w_wptr_o, | |
| input logic [LogDepth:0] async_data_master_w_rptr_i, | |
| input b_chan_t [2**LogDepth-1:0] async_data_master_b_data_i, | |
| input logic [LogDepth:0] async_data_master_b_wptr_i, | |
| output logic [LogDepth:0] async_data_master_b_rptr_o, | |
| output ar_chan_t [2**LogDepth-1:0] async_data_master_ar_data_o, | |
| output logic [LogDepth:0] async_data_master_ar_wptr_o, | |
| input logic [LogDepth:0] async_data_master_ar_rptr_i, | |
| input r_chan_t [2**LogDepth-1:0] async_data_master_r_data_i, | |
| input logic [LogDepth:0] async_data_master_r_wptr_i, | |
| output logic [LogDepth:0] async_data_master_r_rptr_o | |
| ); | |
| cdc_fifo_gray_src #( | |
| .T ( aw_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_src_aw ( | |
| .src_clk_i, | |
| .src_rst_ni, | |
| .src_data_i ( src_req_i.aw ), | |
| .src_valid_i ( src_req_i.aw_valid ), | |
| .src_ready_o ( src_resp_o.aw_ready ), | |
| .async_data_o ( async_data_master_aw_data_o ), | |
| .async_wptr_o ( async_data_master_aw_wptr_o ), | |
| .async_rptr_i ( async_data_master_aw_rptr_i ) | |
| ); | |
| cdc_fifo_gray_src #( | |
| .T ( w_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_src_w ( | |
| .src_clk_i, | |
| .src_rst_ni, | |
| .src_data_i ( src_req_i.w ), | |
| .src_valid_i ( src_req_i.w_valid ), | |
| .src_ready_o ( src_resp_o.w_ready ), | |
| .async_data_o ( async_data_master_w_data_o ), | |
| .async_wptr_o ( async_data_master_w_wptr_o ), | |
| .async_rptr_i ( async_data_master_w_rptr_i ) | |
| ); | |
| cdc_fifo_gray_dst #( | |
| .T ( b_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_dst_b ( | |
| .dst_clk_i ( src_clk_i ), | |
| .dst_rst_ni ( src_rst_ni ), | |
| .dst_data_o ( src_resp_o.b ), | |
| .dst_valid_o ( src_resp_o.b_valid ), | |
| .dst_ready_i ( src_req_i.b_ready ), | |
| .async_data_i ( async_data_master_b_data_i ), | |
| .async_wptr_i ( async_data_master_b_wptr_i ), | |
| .async_rptr_o ( async_data_master_b_rptr_o ) | |
| ); | |
| cdc_fifo_gray_src #( | |
| .T ( ar_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_src_ar ( | |
| .src_clk_i, | |
| .src_rst_ni, | |
| .src_data_i ( src_req_i.ar ), | |
| .src_valid_i ( src_req_i.ar_valid ), | |
| .src_ready_o ( src_resp_o.ar_ready ), | |
| .async_data_o ( async_data_master_ar_data_o ), | |
| .async_wptr_o ( async_data_master_ar_wptr_o ), | |
| .async_rptr_i ( async_data_master_ar_rptr_i ) | |
| ); | |
| cdc_fifo_gray_dst #( | |
| .T ( r_chan_t ), | |
| .LOG_DEPTH ( LogDepth ), | |
| .SYNC_STAGES ( SyncStages ) | |
| ) i_cdc_fifo_gray_dst_r ( | |
| .dst_clk_i ( src_clk_i ), | |
| .dst_rst_ni ( src_rst_ni ), | |
| .dst_data_o ( src_resp_o.r ), | |
| .dst_valid_o ( src_resp_o.r_valid ), | |
| .dst_ready_i ( src_req_i.r_ready ), | |
| .async_data_i ( async_data_master_r_data_i ), | |
| .async_wptr_i ( async_data_master_r_wptr_i ), | |
| .async_rptr_o ( async_data_master_r_rptr_o ) | |
| ); | |
| endmodule | |
| module axi_cdc_src_intf #( | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0, | |
| parameter int unsigned LOG_DEPTH = 1, | |
| parameter int unsigned SYNC_STAGES = 2 | |
| ) ( | |
| input logic src_clk_i, | |
| input logic src_rst_ni, | |
| AXI_BUS.Slave src, | |
| AXI_BUS_ASYNC_GRAY.Master dst | |
| ); | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| b_chan_t b; | |
| logic r_valid; | |
| r_chan_t r; | |
| } resp_t; | |
| req_t src_req; | |
| resp_t src_resp; | |
| assign src_req.aw.id = src.aw_id; | |
| assign src_req.aw.addr = src.aw_addr; | |
| assign src_req.aw.len = src.aw_len; | |
| assign src_req.aw.size = src.aw_size; | |
| assign src_req.aw.burst = src.aw_burst; | |
| assign src_req.aw.lock = src.aw_lock; | |
| assign src_req.aw.cache = src.aw_cache; | |
| assign src_req.aw.prot = src.aw_prot; | |
| assign src_req.aw.qos = src.aw_qos; | |
| assign src_req.aw.region = src.aw_region; | |
| assign src_req.aw.atop = src.aw_atop; | |
| assign src_req.aw.user = src.aw_user; | |
| assign src_req.aw_valid = src.aw_valid; | |
| assign src_req.w.data = src.w_data; | |
| assign src_req.w.strb = src.w_strb; | |
| assign src_req.w.last = src.w_last; | |
| assign src_req.w.user = src.w_user; | |
| assign src_req.w_valid = src.w_valid; | |
| assign src_req.b_ready = src.b_ready; | |
| assign src_req.ar.id = src.ar_id; | |
| assign src_req.ar.addr = src.ar_addr; | |
| assign src_req.ar.len = src.ar_len; | |
| assign src_req.ar.size = src.ar_size; | |
| assign src_req.ar.burst = src.ar_burst; | |
| assign src_req.ar.lock = src.ar_lock; | |
| assign src_req.ar.cache = src.ar_cache; | |
| assign src_req.ar.prot = src.ar_prot; | |
| assign src_req.ar.qos = src.ar_qos; | |
| assign src_req.ar.region = src.ar_region; | |
| assign src_req.ar.user = src.ar_user; | |
| assign src_req.ar_valid = src.ar_valid; | |
| assign src_req.r_ready = src.r_ready; | |
| assign src.aw_ready = src_resp.aw_ready; | |
| assign src.ar_ready = src_resp.ar_ready; | |
| assign src.w_ready = src_resp.w_ready; | |
| assign src.b_valid = src_resp.b_valid; | |
| assign src.b_id = src_resp.b.id; | |
| assign src.b_resp = src_resp.b.resp; | |
| assign src.b_user = src_resp.b.user; | |
| assign src.r_valid = src_resp.r_valid; | |
| assign src.r_id = src_resp.r.id; | |
| assign src.r_data = src_resp.r.data; | |
| assign src.r_resp = src_resp.r.resp; | |
| assign src.r_last = src_resp.r.last; | |
| assign src.r_user = src_resp.r.user; | |
| axi_cdc_src #( | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( req_t ), | |
| .axi_resp_t ( resp_t ), | |
| .LogDepth ( LOG_DEPTH ), | |
| .SyncStages ( SYNC_STAGES ) | |
| ) i_axi_cdc_src ( | |
| .src_clk_i, | |
| .src_rst_ni, | |
| .src_req_i ( src_req ), | |
| .src_resp_o ( src_resp ), | |
| .async_data_master_aw_data_o ( dst.aw_data ), | |
| .async_data_master_aw_wptr_o ( dst.aw_wptr ), | |
| .async_data_master_aw_rptr_i ( dst.aw_rptr ), | |
| .async_data_master_w_data_o ( dst.w_data ), | |
| .async_data_master_w_wptr_o ( dst.w_wptr ), | |
| .async_data_master_w_rptr_i ( dst.w_rptr ), | |
| .async_data_master_b_data_i ( dst.b_data ), | |
| .async_data_master_b_wptr_i ( dst.b_wptr ), | |
| .async_data_master_b_rptr_o ( dst.b_rptr ), | |
| .async_data_master_ar_data_o ( dst.ar_data ), | |
| .async_data_master_ar_wptr_o ( dst.ar_wptr ), | |
| .async_data_master_ar_rptr_i ( dst.ar_rptr ), | |
| .async_data_master_r_data_i ( dst.r_data ), | |
| .async_data_master_r_wptr_i ( dst.r_wptr ), | |
| .async_data_master_r_rptr_o ( dst.r_rptr ) | |
| ); | |
| endmodule | |
| module axi_lite_cdc_src_intf #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned LOG_DEPTH = 1, | |
| parameter int unsigned SYNC_STAGES = 2 | |
| ) ( | |
| input logic src_clk_i, | |
| input logic src_rst_ni, | |
| AXI_BUS.Slave src, | |
| AXI_LITE_ASYNC_GRAY.Master dst | |
| ); | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_t r; | |
| logic r_valid; | |
| } resp_t; | |
| req_t src_req; | |
| resp_t src_resp; | |
| assign src_req.aw.addr = src.aw_addr; | |
| assign src_req.aw.prot = src.aw_prot; | |
| assign src_req.aw_valid = src.aw_valid; | |
| assign src_req.w.data = src.w_data; | |
| assign src_req.w.strb = src.w_strb; | |
| assign src_req.w_valid = src.w_valid; | |
| assign src_req.b_ready = src.b_ready; | |
| assign src_req.ar.addr = src.ar_addr; | |
| assign src_req.ar.prot = src.ar_prot; | |
| assign src_req.ar_valid = src.ar_valid; | |
| assign src_req.r_ready = src.r_ready; | |
| assign src.aw_ready = src_resp.aw_ready; | |
| assign src.ar_ready = src_resp.ar_ready; | |
| assign src.w_ready = src_resp.w_ready; | |
| assign src.b_valid = src_resp.b_valid; | |
| assign src.b_resp = src_resp.b.resp; | |
| assign src.r_valid = src_resp.r_valid; | |
| assign src.r_data = src_resp.r.data; | |
| assign src.r_resp = src_resp.r.resp; | |
| axi_cdc_src #( | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( req_t ), | |
| .axi_resp_t ( resp_t ), | |
| .LogDepth ( LOG_DEPTH ), | |
| .SyncStages ( SYNC_STAGES ) | |
| ) i_axi_cdc_src ( | |
| .src_clk_i, | |
| .src_rst_ni, | |
| .src_req_i ( src_req ), | |
| .src_resp_o ( src_resp ), | |
| .async_data_master_aw_data_o ( dst.aw_data ), | |
| .async_data_master_aw_wptr_o ( dst.aw_wptr ), | |
| .async_data_master_aw_rptr_i ( dst.aw_rptr ), | |
| .async_data_master_w_data_o ( dst.w_data ), | |
| .async_data_master_w_wptr_o ( dst.w_wptr ), | |
| .async_data_master_w_rptr_i ( dst.w_rptr ), | |
| .async_data_master_b_data_i ( dst.b_data ), | |
| .async_data_master_b_wptr_i ( dst.b_wptr ), | |
| .async_data_master_b_rptr_o ( dst.b_rptr ), | |
| .async_data_master_ar_data_o ( dst.ar_data ), | |
| .async_data_master_ar_wptr_o ( dst.ar_wptr ), | |
| .async_data_master_ar_rptr_i ( dst.ar_rptr ), | |
| .async_data_master_r_data_i ( dst.r_data ), | |
| .async_data_master_r_wptr_i ( dst.r_wptr ), | |
| .async_data_master_r_rptr_o ( dst.r_rptr ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_cut #( | |
| parameter bit Bypass = 1'b0, | |
| parameter bit BypassAw = Bypass, | |
| parameter bit BypassW = Bypass, | |
| parameter bit BypassB = Bypass, | |
| parameter bit BypassAr = Bypass, | |
| parameter bit BypassR = Bypass, | |
| parameter type aw_chan_t = logic, | |
| parameter type w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| spill_register #( | |
| .T ( aw_chan_t ), | |
| .Bypass ( BypassAw ) | |
| ) i_reg_aw ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.aw_valid ), | |
| .ready_o ( slv_resp_o.aw_ready ), | |
| .data_i ( slv_req_i.aw ), | |
| .valid_o ( mst_req_o.aw_valid ), | |
| .ready_i ( mst_resp_i.aw_ready ), | |
| .data_o ( mst_req_o.aw ) | |
| ); | |
| spill_register #( | |
| .T ( w_chan_t ), | |
| .Bypass ( BypassW ) | |
| ) i_reg_w ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.w_valid ), | |
| .ready_o ( slv_resp_o.w_ready ), | |
| .data_i ( slv_req_i.w ), | |
| .valid_o ( mst_req_o.w_valid ), | |
| .ready_i ( mst_resp_i.w_ready ), | |
| .data_o ( mst_req_o.w ) | |
| ); | |
| spill_register #( | |
| .T ( b_chan_t ), | |
| .Bypass ( BypassB ) | |
| ) i_reg_b ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_resp_i.b_valid ), | |
| .ready_o ( mst_req_o.b_ready ), | |
| .data_i ( mst_resp_i.b ), | |
| .valid_o ( slv_resp_o.b_valid ), | |
| .ready_i ( slv_req_i.b_ready ), | |
| .data_o ( slv_resp_o.b ) | |
| ); | |
| spill_register #( | |
| .T ( ar_chan_t ), | |
| .Bypass ( BypassAr ) | |
| ) i_reg_ar ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.ar_valid ), | |
| .ready_o ( slv_resp_o.ar_ready ), | |
| .data_i ( slv_req_i.ar ), | |
| .valid_o ( mst_req_o.ar_valid ), | |
| .ready_i ( mst_resp_i.ar_ready ), | |
| .data_o ( mst_req_o.ar ) | |
| ); | |
| spill_register #( | |
| .T ( r_chan_t ), | |
| .Bypass ( BypassR ) | |
| ) i_reg_r ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_resp_i.r_valid ), | |
| .ready_o ( mst_req_o.r_ready ), | |
| .data_i ( mst_resp_i.r ), | |
| .valid_o ( slv_resp_o.r_valid ), | |
| .ready_i ( slv_req_i.r_ready ), | |
| .data_o ( slv_resp_o.r ) | |
| ); | |
| endmodule | |
| module axi_cut_intf #( | |
| parameter bit BYPASS = 1'b0, | |
| parameter bit BYPASS_AW = BYPASS, | |
| parameter bit BYPASS_W = BYPASS, | |
| parameter bit BYPASS_B = BYPASS, | |
| parameter bit BYPASS_AR = BYPASS, | |
| parameter bit BYPASS_R = BYPASS, | |
| parameter int unsigned ADDR_WIDTH = 0, | |
| parameter int unsigned DATA_WIDTH = 0, | |
| parameter int unsigned ID_WIDTH = 0, | |
| parameter int unsigned USER_WIDTH = 0 | |
| ) ( | |
| input logic clk_i , | |
| input logic rst_ni , | |
| AXI_BUS.Slave in , | |
| AXI_BUS.Master out | |
| ); | |
| typedef logic [ID_WIDTH-1:0] id_t; | |
| typedef logic [ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [DATA_WIDTH-1:0] data_t; | |
| typedef logic [DATA_WIDTH/8-1:0] strb_t; | |
| typedef logic [USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| b_chan_t b; | |
| logic r_valid; | |
| r_chan_t r; | |
| } axi_resp_t; | |
| axi_req_t slv_req, mst_req; | |
| axi_resp_t slv_resp, mst_resp; | |
| assign slv_req.aw.id = in.aw_id; | |
| assign slv_req.aw.addr = in.aw_addr; | |
| assign slv_req.aw.len = in.aw_len; | |
| assign slv_req.aw.size = in.aw_size; | |
| assign slv_req.aw.burst = in.aw_burst; | |
| assign slv_req.aw.lock = in.aw_lock; | |
| assign slv_req.aw.cache = in.aw_cache; | |
| assign slv_req.aw.prot = in.aw_prot; | |
| assign slv_req.aw.qos = in.aw_qos; | |
| assign slv_req.aw.region = in.aw_region; | |
| assign slv_req.aw.atop = in.aw_atop; | |
| assign slv_req.aw.user = in.aw_user; | |
| assign slv_req.aw_valid = in.aw_valid; | |
| assign slv_req.w.data = in.w_data; | |
| assign slv_req.w.strb = in.w_strb; | |
| assign slv_req.w.last = in.w_last; | |
| assign slv_req.w.user = in.w_user; | |
| assign slv_req.w_valid = in.w_valid; | |
| assign slv_req.b_ready = in.b_ready; | |
| assign slv_req.ar.id = in.ar_id; | |
| assign slv_req.ar.addr = in.ar_addr; | |
| assign slv_req.ar.len = in.ar_len; | |
| assign slv_req.ar.size = in.ar_size; | |
| assign slv_req.ar.burst = in.ar_burst; | |
| assign slv_req.ar.lock = in.ar_lock; | |
| assign slv_req.ar.cache = in.ar_cache; | |
| assign slv_req.ar.prot = in.ar_prot; | |
| assign slv_req.ar.qos = in.ar_qos; | |
| assign slv_req.ar.region = in.ar_region; | |
| assign slv_req.ar.user = in.ar_user; | |
| assign slv_req.ar_valid = in.ar_valid; | |
| assign slv_req.r_ready = in.r_ready; | |
| assign in.aw_ready = slv_resp.aw_ready; | |
| assign in.ar_ready = slv_resp.ar_ready; | |
| assign in.w_ready = slv_resp.w_ready; | |
| assign in.b_valid = slv_resp.b_valid; | |
| assign in.b_id = slv_resp.b.id; | |
| assign in.b_resp = slv_resp.b.resp; | |
| assign in.b_user = slv_resp.b.user; | |
| assign in.r_valid = slv_resp.r_valid; | |
| assign in.r_id = slv_resp.r.id; | |
| assign in.r_data = slv_resp.r.data; | |
| assign in.r_resp = slv_resp.r.resp; | |
| assign in.r_last = slv_resp.r.last; | |
| assign in.r_user = slv_resp.r.user; | |
| assign out.aw_id = mst_req.aw.id; | |
| assign out.aw_addr = mst_req.aw.addr; | |
| assign out.aw_len = mst_req.aw.len; | |
| assign out.aw_size = mst_req.aw.size; | |
| assign out.aw_burst = mst_req.aw.burst; | |
| assign out.aw_lock = mst_req.aw.lock; | |
| assign out.aw_cache = mst_req.aw.cache; | |
| assign out.aw_prot = mst_req.aw.prot; | |
| assign out.aw_qos = mst_req.aw.qos; | |
| assign out.aw_region = mst_req.aw.region; | |
| assign out.aw_atop = mst_req.aw.atop; | |
| assign out.aw_user = mst_req.aw.user; | |
| assign out.aw_valid = mst_req.aw_valid; | |
| assign out.w_data = mst_req.w.data; | |
| assign out.w_strb = mst_req.w.strb; | |
| assign out.w_last = mst_req.w.last; | |
| assign out.w_user = mst_req.w.user; | |
| assign out.w_valid = mst_req.w_valid; | |
| assign out.b_ready = mst_req.b_ready; | |
| assign out.ar_id = mst_req.ar.id; | |
| assign out.ar_addr = mst_req.ar.addr; | |
| assign out.ar_len = mst_req.ar.len; | |
| assign out.ar_size = mst_req.ar.size; | |
| assign out.ar_burst = mst_req.ar.burst; | |
| assign out.ar_lock = mst_req.ar.lock; | |
| assign out.ar_cache = mst_req.ar.cache; | |
| assign out.ar_prot = mst_req.ar.prot; | |
| assign out.ar_qos = mst_req.ar.qos; | |
| assign out.ar_region = mst_req.ar.region; | |
| assign out.ar_user = mst_req.ar.user; | |
| assign out.ar_valid = mst_req.ar_valid; | |
| assign out.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = out.aw_ready; | |
| assign mst_resp.ar_ready = out.ar_ready; | |
| assign mst_resp.w_ready = out.w_ready; | |
| assign mst_resp.b_valid = out.b_valid; | |
| assign mst_resp.b.id = out.b_id; | |
| assign mst_resp.b.resp = out.b_resp; | |
| assign mst_resp.b.user = out.b_user; | |
| assign mst_resp.r_valid = out.r_valid; | |
| assign mst_resp.r.id = out.r_id; | |
| assign mst_resp.r.data = out.r_data; | |
| assign mst_resp.r.resp = out.r_resp; | |
| assign mst_resp.r.last = out.r_last; | |
| assign mst_resp.r.user = out.r_user; | |
| axi_cut #( | |
| .Bypass ( BYPASS ), | |
| .BypassAw ( BYPASS_AW ), | |
| .BypassW ( BYPASS_W ), | |
| .BypassB ( BYPASS_B ), | |
| .BypassAr ( BYPASS_AR ), | |
| .BypassR ( BYPASS_R ), | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ) | |
| ) i_axi_cut ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_req ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_req_o ( mst_req ), | |
| .mst_resp_i ( mst_resp ) | |
| ); | |
| endmodule | |
| module axi_lite_cut_intf #( | |
| parameter bit BYPASS = 1'b0, | |
| parameter bit BYPASS_AW = BYPASS, | |
| parameter bit BYPASS_W = BYPASS, | |
| parameter bit BYPASS_B = BYPASS, | |
| parameter bit BYPASS_AR = BYPASS, | |
| parameter bit BYPASS_R = BYPASS, | |
| parameter int unsigned ADDR_WIDTH = 0, | |
| parameter int unsigned DATA_WIDTH = 0 | |
| ) ( | |
| input logic clk_i , | |
| input logic rst_ni , | |
| AXI_LITE.Slave in , | |
| AXI_LITE.Master out | |
| ); | |
| typedef logic [ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [DATA_WIDTH-1:0] data_t; | |
| typedef logic [DATA_WIDTH/8-1:0] strb_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_t r; | |
| logic r_valid; | |
| } axi_resp_t; | |
| axi_req_t slv_req, mst_req; | |
| axi_resp_t slv_resp, mst_resp; | |
| assign slv_req.aw.addr = in.aw_addr; | |
| assign slv_req.aw.prot = in.aw_prot; | |
| assign slv_req.aw_valid = in.aw_valid; | |
| assign slv_req.w.data = in.w_data; | |
| assign slv_req.w.strb = in.w_strb; | |
| assign slv_req.w_valid = in.w_valid; | |
| assign slv_req.b_ready = in.b_ready; | |
| assign slv_req.ar.addr = in.ar_addr; | |
| assign slv_req.ar.prot = in.ar_prot; | |
| assign slv_req.ar_valid = in.ar_valid; | |
| assign slv_req.r_ready = in.r_ready; | |
| assign in.aw_ready = slv_resp.aw_ready; | |
| assign in.ar_ready = slv_resp.ar_ready; | |
| assign in.w_ready = slv_resp.w_ready; | |
| assign in.b_valid = slv_resp.b_valid; | |
| assign in.b_resp = slv_resp.b.resp; | |
| assign in.r_valid = slv_resp.r_valid; | |
| assign in.r_data = slv_resp.r.data; | |
| assign in.r_resp = slv_resp.r.resp; | |
| assign out.aw_addr = mst_req.aw.addr; | |
| assign out.aw_prot = mst_req.aw.prot; | |
| assign out.aw_valid = mst_req.aw_valid; | |
| assign out.w_data = mst_req.w.data; | |
| assign out.w_strb = mst_req.w.strb; | |
| assign out.w_valid = mst_req.w_valid; | |
| assign out.b_ready = mst_req.b_ready; | |
| assign out.ar_addr = mst_req.ar.addr; | |
| assign out.ar_prot = mst_req.ar.prot; | |
| assign out.ar_valid = mst_req.ar_valid; | |
| assign out.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = out.aw_ready; | |
| assign mst_resp.ar_ready = out.ar_ready; | |
| assign mst_resp.w_ready = out.w_ready; | |
| assign mst_resp.b_valid = out.b_valid; | |
| assign mst_resp.b.resp = out.b_resp; | |
| assign mst_resp.r_valid = out.r_valid; | |
| assign mst_resp.r.data = out.r_data; | |
| assign mst_resp.r.resp = out.r_resp; | |
| axi_cut #( | |
| .Bypass ( BYPASS ), | |
| .BypassAw ( BYPASS_AW ), | |
| .BypassW ( BYPASS_W ), | |
| .BypassB ( BYPASS_B ), | |
| .BypassAr ( BYPASS_AR ), | |
| .BypassR ( BYPASS_R ), | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ) | |
| ) i_axi_cut ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_req ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_req_o ( mst_req ), | |
| .mst_resp_i ( mst_resp ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_delayer #( | |
| parameter type aw_chan_t = logic, | |
| parameter type w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic, | |
| parameter bit StallRandomInput = 0, | |
| parameter bit StallRandomOutput = 0, | |
| parameter int unsigned FixedDelayInput = 1, | |
| parameter int unsigned FixedDelayOutput = 1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| stream_delay #( | |
| .StallRandom ( StallRandomInput ), | |
| .FixedDelay ( FixedDelayInput ), | |
| .payload_t ( aw_chan_t ) | |
| ) i_stream_delay_aw ( | |
| .clk_i, | |
| .rst_ni, | |
| .payload_i ( slv_req_i.aw ), | |
| .ready_o ( slv_resp_o.aw_ready ), | |
| .valid_i ( slv_req_i.aw_valid ), | |
| .payload_o ( mst_req_o.aw ), | |
| .ready_i ( mst_resp_i.aw_ready ), | |
| .valid_o ( mst_req_o.aw_valid ) | |
| ); | |
| stream_delay #( | |
| .StallRandom ( StallRandomInput ), | |
| .FixedDelay ( FixedDelayInput ), | |
| .payload_t ( ar_chan_t ) | |
| ) i_stream_delay_ar ( | |
| .clk_i, | |
| .rst_ni, | |
| .payload_i ( slv_req_i.ar ), | |
| .ready_o ( slv_resp_o.ar_ready ), | |
| .valid_i ( slv_req_i.ar_valid ), | |
| .payload_o ( mst_req_o.ar ), | |
| .ready_i ( mst_resp_i.ar_ready ), | |
| .valid_o ( mst_req_o.ar_valid ) | |
| ); | |
| stream_delay #( | |
| .StallRandom ( StallRandomInput ), | |
| .FixedDelay ( FixedDelayInput ), | |
| .payload_t ( w_chan_t ) | |
| ) i_stream_delay_w ( | |
| .clk_i, | |
| .rst_ni, | |
| .payload_i ( slv_req_i.w ), | |
| .ready_o ( slv_resp_o.w_ready ), | |
| .valid_i ( slv_req_i.w_valid ), | |
| .payload_o ( mst_req_o.w ), | |
| .ready_i ( mst_resp_i.w_ready ), | |
| .valid_o ( mst_req_o.w_valid ) | |
| ); | |
| stream_delay #( | |
| .StallRandom ( StallRandomOutput ), | |
| .FixedDelay ( FixedDelayOutput ), | |
| .payload_t ( b_chan_t ) | |
| ) i_stream_delay_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .payload_i ( mst_resp_i.b ), | |
| .ready_o ( mst_req_o.b_ready ), | |
| .valid_i ( mst_resp_i.b_valid ), | |
| .payload_o ( slv_resp_o.b ), | |
| .ready_i ( slv_req_i.b_ready ), | |
| .valid_o ( slv_resp_o.b_valid ) | |
| ); | |
| stream_delay #( | |
| .StallRandom ( StallRandomOutput ), | |
| .FixedDelay ( FixedDelayOutput ), | |
| .payload_t ( r_chan_t ) | |
| ) i_stream_delay_r ( | |
| .clk_i, | |
| .rst_ni, | |
| .payload_i ( mst_resp_i.r ), | |
| .ready_o ( mst_req_o.r_ready ), | |
| .valid_i ( mst_resp_i.r_valid ), | |
| .payload_o ( slv_resp_o.r ), | |
| .ready_i ( slv_req_i.r_ready ), | |
| .valid_o ( slv_resp_o.r_valid ) | |
| ); | |
| endmodule | |
| module axi_delayer_intf #( | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0, | |
| parameter bit STALL_RANDOM_INPUT = 0, | |
| parameter bit STALL_RANDOM_OUTPUT = 0, | |
| parameter int unsigned FIXED_DELAY_INPUT = 1, | |
| parameter int unsigned FIXED_DELAY_OUTPUT = 1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| AXI_BUS.Slave slv, | |
| AXI_BUS.Master mst | |
| ); | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| b_chan_t b; | |
| logic r_valid; | |
| r_chan_t r; | |
| } axi_resp_t; | |
| axi_req_t slv_req, mst_req; | |
| axi_resp_t slv_resp, mst_resp; | |
| assign slv_req.aw.id = slv.aw_id; | |
| assign slv_req.aw.addr = slv.aw_addr; | |
| assign slv_req.aw.len = slv.aw_len; | |
| assign slv_req.aw.size = slv.aw_size; | |
| assign slv_req.aw.burst = slv.aw_burst; | |
| assign slv_req.aw.lock = slv.aw_lock; | |
| assign slv_req.aw.cache = slv.aw_cache; | |
| assign slv_req.aw.prot = slv.aw_prot; | |
| assign slv_req.aw.qos = slv.aw_qos; | |
| assign slv_req.aw.region = slv.aw_region; | |
| assign slv_req.aw.atop = slv.aw_atop; | |
| assign slv_req.aw.user = slv.aw_user; | |
| assign slv_req.aw_valid = slv.aw_valid; | |
| assign slv_req.w.data = slv.w_data; | |
| assign slv_req.w.strb = slv.w_strb; | |
| assign slv_req.w.last = slv.w_last; | |
| assign slv_req.w.user = slv.w_user; | |
| assign slv_req.w_valid = slv.w_valid; | |
| assign slv_req.b_ready = slv.b_ready; | |
| assign slv_req.ar.id = slv.ar_id; | |
| assign slv_req.ar.addr = slv.ar_addr; | |
| assign slv_req.ar.len = slv.ar_len; | |
| assign slv_req.ar.size = slv.ar_size; | |
| assign slv_req.ar.burst = slv.ar_burst; | |
| assign slv_req.ar.lock = slv.ar_lock; | |
| assign slv_req.ar.cache = slv.ar_cache; | |
| assign slv_req.ar.prot = slv.ar_prot; | |
| assign slv_req.ar.qos = slv.ar_qos; | |
| assign slv_req.ar.region = slv.ar_region; | |
| assign slv_req.ar.user = slv.ar_user; | |
| assign slv_req.ar_valid = slv.ar_valid; | |
| assign slv_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = slv_resp.aw_ready; | |
| assign slv.ar_ready = slv_resp.ar_ready; | |
| assign slv.w_ready = slv_resp.w_ready; | |
| assign slv.b_valid = slv_resp.b_valid; | |
| assign slv.b_id = slv_resp.b.id; | |
| assign slv.b_resp = slv_resp.b.resp; | |
| assign slv.b_user = slv_resp.b.user; | |
| assign slv.r_valid = slv_resp.r_valid; | |
| assign slv.r_id = slv_resp.r.id; | |
| assign slv.r_data = slv_resp.r.data; | |
| assign slv.r_resp = slv_resp.r.resp; | |
| assign slv.r_last = slv_resp.r.last; | |
| assign slv.r_user = slv_resp.r.user; | |
| assign mst.aw_id = mst_req.aw.id; | |
| assign mst.aw_addr = mst_req.aw.addr; | |
| assign mst.aw_len = mst_req.aw.len; | |
| assign mst.aw_size = mst_req.aw.size; | |
| assign mst.aw_burst = mst_req.aw.burst; | |
| assign mst.aw_lock = mst_req.aw.lock; | |
| assign mst.aw_cache = mst_req.aw.cache; | |
| assign mst.aw_prot = mst_req.aw.prot; | |
| assign mst.aw_qos = mst_req.aw.qos; | |
| assign mst.aw_region = mst_req.aw.region; | |
| assign mst.aw_atop = mst_req.aw.atop; | |
| assign mst.aw_user = mst_req.aw.user; | |
| assign mst.aw_valid = mst_req.aw_valid; | |
| assign mst.w_data = mst_req.w.data; | |
| assign mst.w_strb = mst_req.w.strb; | |
| assign mst.w_last = mst_req.w.last; | |
| assign mst.w_user = mst_req.w.user; | |
| assign mst.w_valid = mst_req.w_valid; | |
| assign mst.b_ready = mst_req.b_ready; | |
| assign mst.ar_id = mst_req.ar.id; | |
| assign mst.ar_addr = mst_req.ar.addr; | |
| assign mst.ar_len = mst_req.ar.len; | |
| assign mst.ar_size = mst_req.ar.size; | |
| assign mst.ar_burst = mst_req.ar.burst; | |
| assign mst.ar_lock = mst_req.ar.lock; | |
| assign mst.ar_cache = mst_req.ar.cache; | |
| assign mst.ar_prot = mst_req.ar.prot; | |
| assign mst.ar_qos = mst_req.ar.qos; | |
| assign mst.ar_region = mst_req.ar.region; | |
| assign mst.ar_user = mst_req.ar.user; | |
| assign mst.ar_valid = mst_req.ar_valid; | |
| assign mst.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = mst.aw_ready; | |
| assign mst_resp.ar_ready = mst.ar_ready; | |
| assign mst_resp.w_ready = mst.w_ready; | |
| assign mst_resp.b_valid = mst.b_valid; | |
| assign mst_resp.b.id = mst.b_id; | |
| assign mst_resp.b.resp = mst.b_resp; | |
| assign mst_resp.b.user = mst.b_user; | |
| assign mst_resp.r_valid = mst.r_valid; | |
| assign mst_resp.r.id = mst.r_id; | |
| assign mst_resp.r.data = mst.r_data; | |
| assign mst_resp.r.resp = mst.r_resp; | |
| assign mst_resp.r.last = mst.r_last; | |
| assign mst_resp.r.user = mst.r_user; | |
| axi_delayer #( | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .StallRandomInput ( STALL_RANDOM_INPUT ), | |
| .StallRandomOutput ( STALL_RANDOM_OUTPUT ), | |
| .FixedDelayInput ( FIXED_DELAY_INPUT ), | |
| .FixedDelayOutput ( FIXED_DELAY_OUTPUT ) | |
| ) i_axi_delayer ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_req ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_req_o ( mst_req ), | |
| .mst_resp_i ( mst_resp ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_demux_simple #( | |
| parameter int unsigned AxiIdWidth = 32'd0, | |
| parameter bit AtopSupport = 1'b1, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic, | |
| parameter int unsigned NoMstPorts = 32'd0, | |
| parameter int unsigned MaxTrans = 32'd8, | |
| parameter int unsigned AxiLookBits = 32'd3, | |
| parameter bit UniqueIds = 1'b0, | |
| parameter int unsigned SelectWidth = (NoMstPorts > 32'd1) ? $clog2(NoMstPorts) : 32'd1, | |
| parameter type select_t = logic [SelectWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| input axi_req_t slv_req_i, | |
| input select_t slv_aw_select_i, | |
| input select_t slv_ar_select_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t [NoMstPorts-1:0] mst_reqs_o, | |
| input axi_resp_t [NoMstPorts-1:0] mst_resps_i | |
| ); | |
| localparam int unsigned IdCounterWidth = cf_math_pkg::idx_width(MaxTrans); | |
| typedef logic [IdCounterWidth-1:0] id_cnt_t; | |
| if (NoMstPorts == 32'h1) begin : gen_no_demux | |
| assign mst_reqs_o[0].aw.id = slv_req_i.aw.id; | |
| assign mst_reqs_o[0].aw.addr = slv_req_i.aw.addr; | |
| assign mst_reqs_o[0].aw.len = slv_req_i.aw.len; | |
| assign mst_reqs_o[0].aw.size = slv_req_i.aw.size; | |
| assign mst_reqs_o[0].aw.burst = slv_req_i.aw.burst; | |
| assign mst_reqs_o[0].aw.lock = slv_req_i.aw.lock; | |
| assign mst_reqs_o[0].aw.cache = slv_req_i.aw.cache; | |
| assign mst_reqs_o[0].aw.prot = slv_req_i.aw.prot; | |
| assign mst_reqs_o[0].aw.qos = slv_req_i.aw.qos; | |
| assign mst_reqs_o[0].aw.region = slv_req_i.aw.region; | |
| assign mst_reqs_o[0].aw.atop = slv_req_i.aw.atop; | |
| assign mst_reqs_o[0].aw.user = slv_req_i.aw.user; | |
| assign mst_reqs_o[0].aw_valid = slv_req_i.aw_valid; | |
| assign mst_reqs_o[0].w.data = slv_req_i.w.data; | |
| assign mst_reqs_o[0].w.strb = slv_req_i.w.strb; | |
| assign mst_reqs_o[0].w.last = slv_req_i.w.last; | |
| assign mst_reqs_o[0].w.user = slv_req_i.w.user; | |
| assign mst_reqs_o[0].w_valid = slv_req_i.w_valid; | |
| assign mst_reqs_o[0].b_ready = slv_req_i.b_ready; | |
| assign mst_reqs_o[0].ar.id = slv_req_i.ar.id; | |
| assign mst_reqs_o[0].ar.addr = slv_req_i.ar.addr; | |
| assign mst_reqs_o[0].ar.len = slv_req_i.ar.len; | |
| assign mst_reqs_o[0].ar.size = slv_req_i.ar.size; | |
| assign mst_reqs_o[0].ar.burst = slv_req_i.ar.burst; | |
| assign mst_reqs_o[0].ar.lock = slv_req_i.ar.lock; | |
| assign mst_reqs_o[0].ar.cache = slv_req_i.ar.cache; | |
| assign mst_reqs_o[0].ar.prot = slv_req_i.ar.prot; | |
| assign mst_reqs_o[0].ar.qos = slv_req_i.ar.qos; | |
| assign mst_reqs_o[0].ar.region = slv_req_i.ar.region; | |
| assign mst_reqs_o[0].ar.user = slv_req_i.ar.user; | |
| assign mst_reqs_o[0].ar_valid = slv_req_i.ar_valid; | |
| assign mst_reqs_o[0].r_ready = slv_req_i.r_ready; | |
| assign slv_resp_o.aw_ready = mst_resps_i[0].aw_ready; | |
| assign slv_resp_o.ar_ready = mst_resps_i[0].ar_ready; | |
| assign slv_resp_o.w_ready = mst_resps_i[0].w_ready; | |
| assign slv_resp_o.b_valid = mst_resps_i[0].b_valid; | |
| assign slv_resp_o.b.id = mst_resps_i[0].b.id; | |
| assign slv_resp_o.b.resp = mst_resps_i[0].b.resp; | |
| assign slv_resp_o.b.user = mst_resps_i[0].b.user; | |
| assign slv_resp_o.r_valid = mst_resps_i[0].r_valid; | |
| assign slv_resp_o.r.id = mst_resps_i[0].r.id; | |
| assign slv_resp_o.r.data = mst_resps_i[0].r.data; | |
| assign slv_resp_o.r.resp = mst_resps_i[0].r.resp; | |
| assign slv_resp_o.r.last = mst_resps_i[0].r.last; | |
| assign slv_resp_o.r.user = mst_resps_i[0].r.user; | |
| end else begin | |
| logic lock_aw_valid_d, lock_aw_valid_q, load_aw_lock; | |
| logic aw_valid, aw_ready; | |
| select_t lookup_aw_select; | |
| logic aw_select_occupied, aw_id_cnt_full; | |
| logic atop_inject; | |
| select_t w_select, w_select_q; | |
| logic w_select_valid; | |
| id_cnt_t w_open; | |
| logic w_cnt_up, w_cnt_down; | |
| logic [NoMstPorts-1:0] mst_b_valids, mst_b_readies; | |
| select_t lookup_ar_select; | |
| logic ar_select_occupied, ar_id_cnt_full; | |
| logic ar_push; | |
| logic lock_ar_valid_d, lock_ar_valid_q, load_ar_lock; | |
| logic ar_valid, ar_ready; | |
| logic [NoMstPorts-1:0] mst_r_valids, mst_r_readies; | |
| always_comb begin | |
| slv_resp_o.aw_ready = 1'b0; | |
| aw_valid = 1'b0; | |
| lock_aw_valid_d = lock_aw_valid_q; | |
| load_aw_lock = 1'b0; | |
| w_cnt_up = 1'b0; | |
| atop_inject = 1'b0; | |
| if (lock_aw_valid_q) begin | |
| aw_valid = 1'b1; | |
| if (aw_ready) begin | |
| slv_resp_o.aw_ready = 1'b1; | |
| lock_aw_valid_d = 1'b0; | |
| load_aw_lock = 1'b1; | |
| atop_inject = slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; | |
| end | |
| end else begin | |
| if (!aw_id_cnt_full && (w_open != {IdCounterWidth{1'b1}}) && | |
| (!(ar_id_cnt_full && slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP]) || | |
| !AtopSupport)) begin | |
| if (slv_req_i.aw_valid && | |
| ((w_open == '0) || (w_select == slv_aw_select_i)) && | |
| (!aw_select_occupied || (slv_aw_select_i == lookup_aw_select))) begin | |
| aw_valid = 1'b1; | |
| w_cnt_up = 1'b1; | |
| if (aw_ready) begin | |
| slv_resp_o.aw_ready = 1'b1; | |
| atop_inject = slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP] & AtopSupport; | |
| end else begin | |
| lock_aw_valid_d = 1'b1; | |
| load_aw_lock = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| lock_aw_valid_q <= ('0); | |
| end else begin | |
| if (load_aw_lock) begin | |
| lock_aw_valid_q <= (lock_aw_valid_d); | |
| end | |
| end | |
| end | |
| if (UniqueIds) begin : gen_unique_ids_aw | |
| assign lookup_aw_select = slv_aw_select_i; | |
| assign aw_select_occupied = 1'b0; | |
| assign aw_id_cnt_full = 1'b0; | |
| end else begin : gen_aw_id_counter | |
| axi_demux_id_counters #( | |
| .AxiIdBits ( AxiLookBits ), | |
| .CounterWidth ( IdCounterWidth ), | |
| .mst_port_select_t ( select_t ) | |
| ) i_aw_id_counter ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .lookup_axi_id_i ( slv_req_i.aw.id[0+:AxiLookBits] ), | |
| .lookup_mst_select_o ( lookup_aw_select ), | |
| .lookup_mst_select_occupied_o ( aw_select_occupied ), | |
| .full_o ( aw_id_cnt_full ), | |
| .inject_axi_id_i ( '0 ), | |
| .inject_i ( 1'b0 ), | |
| .push_axi_id_i ( slv_req_i.aw.id[0+:AxiLookBits] ), | |
| .push_mst_select_i ( slv_aw_select_i ), | |
| .push_i ( w_cnt_up ), | |
| .pop_axi_id_i ( slv_resp_o.b.id[0+:AxiLookBits] ), | |
| .pop_i ( slv_resp_o.b_valid & slv_req_i.b_ready ), | |
| .any_outstanding_trx_o ( ) | |
| ); | |
| end | |
| counter #( | |
| .WIDTH ( IdCounterWidth ), | |
| .STICKY_OVERFLOW ( 1'b0 ) | |
| ) i_counter_open_w ( | |
| .clk_i, | |
| .rst_ni, | |
| .clear_i ( 1'b0 ), | |
| .en_i ( w_cnt_up ^ w_cnt_down ), | |
| .load_i ( 1'b0 ), | |
| .down_i ( w_cnt_down ), | |
| .d_i ( '0 ), | |
| .q_o ( w_open ), | |
| .overflow_o ( ) | |
| ); | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| w_select_q <= (select_t'(0)); | |
| end else begin | |
| if (w_cnt_up) begin | |
| w_select_q <= (slv_aw_select_i); | |
| end | |
| end | |
| end | |
| assign w_select = (|w_open) ? w_select_q : slv_aw_select_i; | |
| assign w_select_valid = w_cnt_up | (|w_open); | |
| logic [cf_math_pkg::idx_width(NoMstPorts)-1:0] b_idx; | |
| rr_arb_tree #( | |
| .NumIn ( NoMstPorts ), | |
| .DataType ( logic ), | |
| .AxiVldRdy( 1'b1 ), | |
| .LockIn ( 1'b1 ) | |
| ) i_b_mux ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i( 1'b0 ), | |
| .rr_i ( '0 ), | |
| .req_i ( mst_b_valids ), | |
| .gnt_o ( mst_b_readies ), | |
| .data_i ( '0 ), | |
| .gnt_i ( slv_req_i.b_ready ), | |
| .req_o ( slv_resp_o.b_valid ), | |
| .data_o ( ), | |
| .idx_o ( b_idx ) | |
| ); | |
| always_comb begin | |
| if (slv_resp_o.b_valid) begin | |
| slv_resp_o.b.id = mst_resps_i[b_idx].b.id; | |
| slv_resp_o.b.resp = mst_resps_i[b_idx].b.resp; | |
| slv_resp_o.b.user = mst_resps_i[b_idx].b.user; | |
| end else begin | |
| slv_resp_o.b = '0; | |
| end | |
| end | |
| always_comb begin | |
| slv_resp_o.ar_ready = 1'b0; | |
| ar_valid = 1'b0; | |
| lock_ar_valid_d = lock_ar_valid_q; | |
| load_ar_lock = 1'b0; | |
| ar_push = 1'b0; | |
| if (lock_ar_valid_q) begin | |
| ar_valid = 1'b1; | |
| if (ar_ready) begin | |
| slv_resp_o.ar_ready = 1'b1; | |
| ar_push = 1'b1; | |
| lock_ar_valid_d = 1'b0; | |
| load_ar_lock = 1'b1; | |
| end | |
| end else begin | |
| if (!ar_id_cnt_full) begin | |
| if (slv_req_i.ar_valid && (!ar_select_occupied || | |
| (slv_ar_select_i == lookup_ar_select))) begin | |
| ar_valid = 1'b1; | |
| if (ar_ready) begin | |
| slv_resp_o.ar_ready = 1'b1; | |
| ar_push = 1'b1; | |
| end else begin | |
| lock_ar_valid_d = 1'b1; | |
| load_ar_lock = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| lock_ar_valid_q <= ('0); | |
| end else begin | |
| if (load_ar_lock) begin | |
| lock_ar_valid_q <= (lock_ar_valid_d); | |
| end | |
| end | |
| end | |
| if (UniqueIds) begin : gen_unique_ids_ar | |
| assign lookup_ar_select = slv_ar_select_i; | |
| assign ar_select_occupied = 1'b0; | |
| assign ar_id_cnt_full = 1'b0; | |
| end else begin : gen_ar_id_counter | |
| axi_demux_id_counters #( | |
| .AxiIdBits ( AxiLookBits ), | |
| .CounterWidth ( IdCounterWidth ), | |
| .mst_port_select_t ( select_t ) | |
| ) i_ar_id_counter ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .lookup_axi_id_i ( slv_req_i.ar.id[0+:AxiLookBits] ), | |
| .lookup_mst_select_o ( lookup_ar_select ), | |
| .lookup_mst_select_occupied_o ( ar_select_occupied ), | |
| .full_o ( ar_id_cnt_full ), | |
| .inject_axi_id_i ( slv_req_i.aw.id[0+:AxiLookBits] ), | |
| .inject_i ( atop_inject ), | |
| .push_axi_id_i ( slv_req_i.ar.id[0+:AxiLookBits] ), | |
| .push_mst_select_i ( slv_ar_select_i ), | |
| .push_i ( ar_push ), | |
| .pop_axi_id_i ( slv_resp_o.r.id[0+:AxiLookBits] ), | |
| .pop_i ( slv_resp_o.r_valid & slv_req_i.r_ready & slv_resp_o.r.last ), | |
| .any_outstanding_trx_o ( ) | |
| ); | |
| end | |
| logic [cf_math_pkg::idx_width(NoMstPorts)-1:0] r_idx; | |
| rr_arb_tree #( | |
| .NumIn ( NoMstPorts ), | |
| .DataType ( logic ), | |
| .AxiVldRdy( 1'b1 ), | |
| .LockIn ( 1'b1 ) | |
| ) i_r_mux ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i( 1'b0 ), | |
| .rr_i ( '0 ), | |
| .req_i ( mst_r_valids ), | |
| .gnt_o ( mst_r_readies ), | |
| .data_i ( '0 ), | |
| .gnt_i ( slv_req_i.r_ready ), | |
| .req_o ( slv_resp_o.r_valid ), | |
| .data_o (), | |
| .idx_o ( r_idx ) | |
| ); | |
| always_comb begin | |
| if (slv_resp_o.r_valid) begin | |
| slv_resp_o.r.id = mst_resps_i[r_idx].r.id; | |
| slv_resp_o.r.data = mst_resps_i[r_idx].r.data; | |
| slv_resp_o.r.resp = mst_resps_i[r_idx].r.resp; | |
| slv_resp_o.r.last = mst_resps_i[r_idx].r.last; | |
| slv_resp_o.r.user = mst_resps_i[r_idx].r.user; | |
| end else begin | |
| slv_resp_o.r = '0; | |
| end | |
| end | |
| assign ar_ready = ar_valid & mst_resps_i[slv_ar_select_i].ar_ready; | |
| assign aw_ready = aw_valid & mst_resps_i[slv_aw_select_i].aw_ready; | |
| always_comb begin | |
| mst_reqs_o = '0; | |
| slv_resp_o.w_ready = 1'b0; | |
| w_cnt_down = 1'b0; | |
| for (int unsigned i = 0; i < NoMstPorts; i++) begin | |
| mst_reqs_o[i].aw = slv_req_i.aw; | |
| mst_reqs_o[i].aw_valid = 1'b0; | |
| if (aw_valid && (slv_aw_select_i == i)) begin | |
| mst_reqs_o[i].aw_valid = 1'b1; | |
| end | |
| mst_reqs_o[i].w = slv_req_i.w; | |
| mst_reqs_o[i].w_valid = 1'b0; | |
| if (w_select_valid && (w_select == i)) begin | |
| mst_reqs_o[i].w_valid = slv_req_i.w_valid; | |
| slv_resp_o.w_ready = mst_resps_i[i].w_ready; | |
| w_cnt_down = slv_req_i.w_valid & mst_resps_i[i].w_ready & slv_req_i.w.last; | |
| end | |
| mst_reqs_o[i].b_ready = mst_b_readies[i]; | |
| mst_reqs_o[i].ar = slv_req_i.ar; | |
| mst_reqs_o[i].ar_valid = 1'b0; | |
| if (ar_valid && (slv_ar_select_i == i)) begin | |
| mst_reqs_o[i].ar_valid = 1'b1; | |
| end | |
| mst_reqs_o[i].r_ready = mst_r_readies[i]; | |
| end | |
| end | |
| for (genvar i = 0; i < NoMstPorts; i++) begin : gen_b_channels | |
| assign mst_b_valids[i] = mst_resps_i[i].b_valid; | |
| assign mst_r_valids[i] = mst_resps_i[i].r_valid; | |
| end | |
| end | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_dw_downsizer #( | |
| parameter int unsigned AxiMaxReads = 1 , | |
| parameter int unsigned AxiSlvPortDataWidth = 8 , | |
| parameter int unsigned AxiMstPortDataWidth = 8 , | |
| parameter int unsigned AxiAddrWidth = 1 , | |
| parameter int unsigned AxiIdWidth = 1 , | |
| parameter type aw_chan_t = logic, | |
| parameter type mst_w_chan_t = logic, | |
| parameter type slv_w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type mst_r_chan_t = logic, | |
| parameter type slv_r_chan_t = logic, | |
| parameter type axi_mst_req_t = logic, | |
| parameter type axi_mst_resp_t = logic, | |
| parameter type axi_slv_req_t = logic, | |
| parameter type axi_slv_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_slv_req_t slv_req_i, | |
| output axi_slv_resp_t slv_resp_o, | |
| output axi_mst_req_t mst_req_o, | |
| input axi_mst_resp_t mst_resp_i | |
| ); | |
| import axi_pkg::aligned_addr; | |
| import axi_pkg::modifiable ; | |
| import cf_math_pkg::idx_width; | |
| localparam TranIdWidth = AxiMaxReads > 1 ? $clog2(AxiMaxReads) : 1; | |
| typedef logic [TranIdWidth-1:0] tran_id_t; | |
| localparam AxiSlvPortStrbWidth = AxiSlvPortDataWidth / 8; | |
| localparam AxiMstPortStrbWidth = AxiMstPortDataWidth / 8; | |
| localparam AxiSlvPortMaxSize = $clog2(AxiSlvPortStrbWidth); | |
| localparam AxiMstPortMaxSize = $clog2(AxiMstPortStrbWidth); | |
| localparam SlvPortByteMask = AxiSlvPortStrbWidth - 1; | |
| localparam MstPortByteMask = AxiMstPortStrbWidth - 1; | |
| typedef logic [AxiMstPortStrbWidth-1:0][7:0] mst_data_t; | |
| typedef logic [AxiSlvPortStrbWidth-1:0][7:0] slv_data_t; | |
| typedef logic [AxiAddrWidth-1:0] addr_t; | |
| typedef logic [AxiIdWidth-1:0] id_t; | |
| typedef logic [$clog2(AxiSlvPortStrbWidth/AxiMstPortStrbWidth) + 7:0] burst_len_t; | |
| axi_mst_req_t mst_req; | |
| axi_mst_resp_t mst_resp; | |
| slv_r_chan_t [AxiMaxReads-1:0] slv_r_tran; | |
| logic [AxiMaxReads-1:0] slv_r_valid_tran; | |
| logic [AxiMaxReads-1:0] slv_r_ready_tran; | |
| rr_arb_tree #( | |
| .NumIn (AxiMaxReads ), | |
| .DataType (slv_r_chan_t), | |
| .AxiVldRdy(1'b1 ), | |
| .ExtPrio (1'b0 ), | |
| .LockIn (1'b1 ) | |
| ) i_slv_r_arb ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .flush_i(1'b0 ), | |
| .rr_i ('0 ), | |
| .req_i (slv_r_valid_tran ), | |
| .gnt_o (slv_r_ready_tran ), | |
| .data_i (slv_r_tran ), | |
| .gnt_i (slv_req_i.r_ready ), | |
| .req_o (slv_resp_o.r_valid), | |
| .data_o (slv_resp_o.r ), | |
| .idx_o ( ) | |
| ); | |
| logic [AxiMaxReads-1:0] mst_r_ready_tran; | |
| assign mst_req.r_ready = |mst_r_ready_tran; | |
| id_t arb_slv_ar_id; | |
| logic arb_slv_ar_req; | |
| logic arb_slv_ar_gnt; | |
| logic [AxiMaxReads-1:0] arb_slv_ar_gnt_tran; | |
| logic inject_aw_into_ar; | |
| logic inject_aw_into_ar_req; | |
| logic inject_aw_into_ar_gnt; | |
| assign arb_slv_ar_gnt = |arb_slv_ar_gnt_tran; | |
| rr_arb_tree #( | |
| .NumIn (2 ), | |
| .DataWidth (AxiIdWidth), | |
| .ExtPrio (1'b0 ), | |
| .AxiVldRdy (1'b1 ), | |
| .LockIn (1'b0 ) | |
| ) i_slv_ar_arb ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .flush_i (1'b0 ), | |
| .rr_i ('0 ), | |
| .req_i ({inject_aw_into_ar_req, slv_req_i.ar_valid} ), | |
| .gnt_o ({inject_aw_into_ar_gnt, slv_resp_o.ar_ready}), | |
| .data_i ({slv_req_i.aw.id, slv_req_i.ar.id} ), | |
| .req_o (arb_slv_ar_req ), | |
| .gnt_i (arb_slv_ar_gnt ), | |
| .data_o (arb_slv_ar_id ), | |
| .idx_o (inject_aw_into_ar ) | |
| ); | |
| ar_chan_t [AxiMaxReads-1:0] mst_ar_tran; | |
| id_t [AxiMaxReads-1:0] mst_ar_id; | |
| logic [AxiMaxReads-1:0] mst_ar_valid_tran; | |
| logic [AxiMaxReads-1:0] mst_ar_ready_tran; | |
| tran_id_t mst_req_idx; | |
| rr_arb_tree #( | |
| .NumIn (AxiMaxReads), | |
| .DataType (ar_chan_t ), | |
| .AxiVldRdy(1'b1 ), | |
| .ExtPrio (1'b0 ), | |
| .LockIn (1'b1 ) | |
| ) i_mst_ar_arb ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .flush_i(1'b0 ), | |
| .rr_i ('0 ), | |
| .req_i (mst_ar_valid_tran), | |
| .gnt_o (mst_ar_ready_tran), | |
| .data_i (mst_ar_tran ), | |
| .gnt_i (mst_resp.ar_ready), | |
| .req_o (mst_req.ar_valid ), | |
| .data_o (mst_req.ar ), | |
| .idx_o (mst_req_idx ) | |
| ); | |
| axi_mst_req_t axi_err_req; | |
| axi_mst_resp_t axi_err_resp; | |
| axi_err_slv #( | |
| .AxiIdWidth(AxiIdWidth ), | |
| .Resp (axi_pkg::RESP_SLVERR), | |
| .axi_req_t (axi_mst_req_t ), | |
| .axi_resp_t(axi_mst_resp_t ) | |
| ) i_axi_err_slv ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .test_i (1'b0 ), | |
| .slv_req_i (axi_err_req ), | |
| .slv_resp_o(axi_err_resp) | |
| ); | |
| logic [AxiMaxReads-1:0] mst_req_ar_err; | |
| logic mst_req_aw_err; | |
| axi_demux #( | |
| .AxiIdWidth (AxiIdWidth ), | |
| .AxiLookBits(AxiIdWidth ), | |
| .aw_chan_t (aw_chan_t ), | |
| .w_chan_t (mst_w_chan_t ), | |
| .b_chan_t (b_chan_t ), | |
| .ar_chan_t (ar_chan_t ), | |
| .r_chan_t (mst_r_chan_t ), | |
| .axi_req_t (axi_mst_req_t ), | |
| .axi_resp_t (axi_mst_resp_t), | |
| .NoMstPorts (2 ), | |
| .MaxTrans (AxiMaxReads ), | |
| .SpillAw (1'b1 ) | |
| ) i_axi_demux ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .test_i (1'b0 ), | |
| .mst_reqs_o ({axi_err_req, mst_req_o} ), | |
| .mst_resps_i ({axi_err_resp, mst_resp_i} ), | |
| .slv_ar_select_i(mst_req_ar_err[mst_req_idx]), | |
| .slv_aw_select_i(mst_req_aw_err ), | |
| .slv_req_i (mst_req ), | |
| .slv_resp_o (mst_resp ) | |
| ); | |
| typedef enum logic [2:0] { | |
| R_IDLE , | |
| R_INJECT_AW , | |
| R_PASSTHROUGH , | |
| R_INCR_DOWNSIZE, | |
| R_SPLIT_INCR_DOWNSIZE | |
| } r_state_e; | |
| typedef struct packed { | |
| ar_chan_t ar ; | |
| logic ar_valid ; | |
| logic ar_throw_error ; | |
| slv_r_chan_t r ; | |
| logic r_valid ; | |
| burst_len_t burst_len ; | |
| axi_pkg::size_t orig_ar_size; | |
| logic injected_aw ; | |
| } r_req_t; | |
| typedef struct packed { | |
| aw_chan_t aw ; | |
| logic aw_valid ; | |
| logic aw_throw_error ; | |
| burst_len_t burst_len ; | |
| axi_pkg::len_t orig_aw_len ; | |
| axi_pkg::burst_t orig_aw_burst; | |
| axi_pkg::resp_t burst_resp ; | |
| axi_pkg::size_t orig_aw_size ; | |
| } w_req_t; | |
| w_req_t w_req_d, w_req_q; | |
| logic [AxiMaxReads-1:0] idle_read_downsizer; | |
| tran_id_t idx_ar_downsizer; | |
| tran_id_t idx_idle_downsizer; | |
| lzc #( | |
| .WIDTH(AxiMaxReads) | |
| ) i_idle_lzc ( | |
| .in_i (idle_read_downsizer), | |
| .cnt_o (idx_idle_downsizer ), | |
| .empty_o( ) | |
| ); | |
| logic [AxiMaxReads-1:0] id_clash_downsizer; | |
| tran_id_t idx_id_clash_downsizer; | |
| for (genvar t = 0; t < AxiMaxReads; t++) begin: gen_id_clash | |
| assign id_clash_downsizer[t] = arb_slv_ar_id == mst_ar_id[t] && !idle_read_downsizer[t]; | |
| end | |
| onehot_to_bin #( | |
| .ONEHOT_WIDTH(AxiMaxReads) | |
| ) i_id_clash_onehot_to_bin ( | |
| .onehot(id_clash_downsizer ), | |
| .bin (idx_id_clash_downsizer) | |
| ); | |
| assign idx_ar_downsizer = (|id_clash_downsizer) ? idx_id_clash_downsizer : idx_idle_downsizer; | |
| logic [AxiMaxReads-1:0] idqueue_push; | |
| logic [AxiMaxReads-1:0] idqueue_pop; | |
| tran_id_t idqueue_id; | |
| logic idqueue_valid; | |
| id_queue #( | |
| .ID_WIDTH(AxiIdWidth ), | |
| .CAPACITY(AxiMaxReads), | |
| .data_t (tran_id_t ) | |
| ) i_read_id_queue ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .inp_id_i (arb_slv_ar_id ), | |
| .inp_data_i (idx_ar_downsizer), | |
| .inp_req_i (|idqueue_push ), | |
| .inp_gnt_o ( ), | |
| .oup_id_i (mst_resp.r.id ), | |
| .oup_pop_i (|idqueue_pop ), | |
| .oup_req_i (1'b1 ), | |
| .oup_data_o (idqueue_id ), | |
| .oup_data_valid_o(idqueue_valid ), | |
| .oup_gnt_o ( ), | |
| .exists_data_i ('0 ), | |
| .exists_mask_i ('0 ), | |
| .exists_req_i ('0 ), | |
| .exists_o ( ), | |
| .exists_gnt_o ( ), | |
| .full_o ( ), | |
| .empty_o ( ) | |
| ); | |
| for (genvar t = 0; unsigned'(t) < AxiMaxReads; t++) begin: gen_read_downsizer | |
| r_state_e r_state_d, r_state_q; | |
| r_req_t r_req_d , r_req_q ; | |
| assign idle_read_downsizer[t] = (r_state_q == R_IDLE) || (r_state_q == R_INJECT_AW); | |
| slv_data_t r_data; | |
| always_comb begin | |
| r_state_d = r_state_q; | |
| r_req_d = r_req_q ; | |
| mst_ar_tran[t] = r_req_q.ar ; | |
| mst_ar_id[t] = r_req_q.ar.id ; | |
| mst_ar_valid_tran[t] = r_req_q.ar_valid; | |
| mst_req_ar_err[t] = r_req_q.ar_throw_error; | |
| slv_r_tran[t] = r_req_q.r ; | |
| slv_r_valid_tran[t] = r_req_q.r_valid; | |
| idqueue_push[t] = '0; | |
| idqueue_pop[t] = '0; | |
| arb_slv_ar_gnt_tran[t] = 1'b0; | |
| mst_r_ready_tran[t] = 1'b0; | |
| if (mst_ar_valid_tran[t] && mst_ar_ready_tran[t]) begin | |
| r_req_d.ar_valid = 1'b0; | |
| r_req_d.ar_throw_error = 1'b0; | |
| end | |
| r_data = r_req_q.r.data; | |
| case (r_state_q) | |
| R_IDLE : begin | |
| r_req_d.ar = '0; | |
| r_req_d.r = '0; | |
| if (arb_slv_ar_req && (idx_ar_downsizer == t)) begin | |
| arb_slv_ar_gnt_tran[t] = 1'b1; | |
| idqueue_push[t] = 1'b1; | |
| if (inject_aw_into_ar) begin | |
| r_state_d = R_INJECT_AW; | |
| end else begin | |
| r_state_d = R_PASSTHROUGH; | |
| r_req_d.ar = slv_req_i.ar ; | |
| r_req_d.ar_valid = 1'b1 ; | |
| r_req_d.burst_len = slv_req_i.ar.len ; | |
| r_req_d.orig_ar_size = slv_req_i.ar.size ; | |
| r_req_d.injected_aw = 1'b0 ; | |
| r_req_d.r.resp = axi_pkg::RESP_EXOKAY; | |
| case (r_req_d.ar.burst) | |
| axi_pkg::BURST_INCR : begin | |
| automatic addr_t size_mask; | |
| automatic addr_t conv_ratio; | |
| automatic addr_t align_adj; | |
| size_mask = (1 << r_req_d.ar.size) - 1 ; | |
| conv_ratio = ((1 << r_req_d.ar.size) + AxiMstPortStrbWidth - 1) / AxiMstPortStrbWidth; | |
| align_adj = (r_req_d.ar.addr & size_mask & ~MstPortByteMask) / AxiMstPortStrbWidth; | |
| r_req_d.burst_len = (r_req_d.ar.len + 1) * conv_ratio - align_adj - 1 ; | |
| if (conv_ratio != 1) begin | |
| r_req_d.ar.size = AxiMstPortMaxSize; | |
| if (r_req_d.burst_len <= 255) begin | |
| r_state_d = R_INCR_DOWNSIZE ; | |
| r_req_d.ar.len = r_req_d.burst_len; | |
| end else begin | |
| r_state_d = R_SPLIT_INCR_DOWNSIZE; | |
| r_req_d.ar.len = 255 - align_adj ; | |
| end | |
| end | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| if (r_req_d.ar.len == '0) begin | |
| automatic addr_t size_mask; | |
| automatic addr_t conv_ratio; | |
| automatic addr_t align_adj; | |
| size_mask = (1 << r_req_d.ar.size) - 1 ; | |
| conv_ratio = ((1 << r_req_d.ar.size) + AxiMstPortStrbWidth - 1) / AxiMstPortStrbWidth; | |
| align_adj = (r_req_d.ar.addr & size_mask & ~MstPortByteMask) / AxiMstPortStrbWidth; | |
| r_req_d.burst_len = (conv_ratio >= align_adj + 1) ? (conv_ratio - align_adj - 1) : 0 ; | |
| if (conv_ratio != 1) begin | |
| r_state_d = R_INCR_DOWNSIZE ; | |
| r_req_d.ar.len = r_req_d.burst_len ; | |
| r_req_d.ar.size = AxiMstPortMaxSize ; | |
| r_req_d.ar.burst = axi_pkg::BURST_INCR; | |
| end | |
| end else begin | |
| r_req_d.ar_throw_error = 1'b1; | |
| end | |
| end | |
| axi_pkg::BURST_WRAP: begin | |
| r_state_d = R_PASSTHROUGH; | |
| r_req_d.ar_throw_error = 1'b1 ; | |
| end | |
| default: ; | |
| endcase | |
| end | |
| end | |
| end | |
| R_INJECT_AW : begin | |
| r_req_d.ar.id = w_req_q.aw.id ; | |
| r_req_d.ar.addr = w_req_q.aw.addr ; | |
| r_req_d.ar.size = w_req_q.orig_aw_size ; | |
| r_req_d.ar.burst = w_req_q.orig_aw_burst; | |
| r_req_d.ar.len = w_req_q.orig_aw_len ; | |
| r_req_d.ar.lock = w_req_q.aw.lock ; | |
| r_req_d.ar.cache = w_req_q.aw.cache ; | |
| r_req_d.ar.prot = w_req_q.aw.prot ; | |
| r_req_d.ar.qos = w_req_q.aw.qos ; | |
| r_req_d.ar.region = w_req_q.aw.region ; | |
| r_req_d.ar.user = w_req_q.aw.user ; | |
| r_req_d.ar_valid = 1'b0 ; | |
| r_req_d.burst_len = w_req_q.orig_aw_len ; | |
| r_req_d.orig_ar_size = w_req_q.orig_aw_size ; | |
| r_req_d.injected_aw = 1'b1 ; | |
| r_req_d.r.resp = axi_pkg::RESP_EXOKAY ; | |
| r_state_d = R_PASSTHROUGH; | |
| case (r_req_d.ar.burst) | |
| axi_pkg::BURST_INCR : begin | |
| automatic addr_t size_mask; | |
| automatic addr_t conv_ratio; | |
| automatic addr_t align_adj; | |
| size_mask = (1 << r_req_d.ar.size) - 1 ; | |
| conv_ratio = ((1 << r_req_d.ar.size) + AxiMstPortStrbWidth - 1) / AxiMstPortStrbWidth; | |
| align_adj = (r_req_d.ar.addr & size_mask & ~MstPortByteMask) / AxiMstPortStrbWidth; | |
| r_req_d.burst_len = (r_req_d.ar.len + 1) * conv_ratio - align_adj - 1 ; | |
| if (conv_ratio != 1) begin | |
| r_req_d.ar.size = AxiMstPortMaxSize; | |
| if (r_req_d.burst_len <= 255) begin | |
| r_state_d = R_INCR_DOWNSIZE ; | |
| r_req_d.ar.len = r_req_d.burst_len; | |
| end else begin | |
| r_state_d = R_SPLIT_INCR_DOWNSIZE; | |
| r_req_d.ar.len = 255 - align_adj ; | |
| end | |
| end | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| if (r_req_d.ar.len == '0) begin | |
| automatic addr_t size_mask; | |
| automatic addr_t conv_ratio; | |
| automatic addr_t align_adj; | |
| size_mask = (1 << r_req_d.ar.size) - 1 ; | |
| conv_ratio = ((1 << r_req_d.ar.size) + AxiMstPortStrbWidth - 1) / AxiMstPortStrbWidth; | |
| align_adj = (r_req_d.ar.addr & size_mask & ~MstPortByteMask) / AxiMstPortStrbWidth; | |
| r_req_d.burst_len = (conv_ratio >= align_adj + 1) ? (conv_ratio - align_adj - 1) : 0; | |
| if (conv_ratio != 1) begin | |
| r_state_d = R_INCR_DOWNSIZE ; | |
| r_req_d.ar.len = r_req_d.burst_len ; | |
| r_req_d.ar.size = AxiMstPortMaxSize ; | |
| r_req_d.ar.burst = axi_pkg::BURST_INCR; | |
| end | |
| end else begin | |
| r_req_d.ar_throw_error = 1'b1; | |
| end | |
| end | |
| axi_pkg::BURST_WRAP: begin | |
| r_state_d = R_PASSTHROUGH; | |
| r_req_d.ar_throw_error = 1'b1 ; | |
| end | |
| default: ; | |
| endcase | |
| end | |
| R_PASSTHROUGH, R_INCR_DOWNSIZE, R_SPLIT_INCR_DOWNSIZE: begin | |
| if (slv_r_valid_tran[t] && slv_r_ready_tran[t]) begin | |
| r_req_d.r = '0 ; | |
| r_req_d.r_valid = 1'b0; | |
| r_data = '0 ; | |
| end | |
| if (!r_req_q.ar_valid) begin | |
| if ((idqueue_id == t) && idqueue_valid) begin | |
| if (!slv_r_valid_tran[t] || (slv_r_valid_tran[t] && slv_r_ready_tran[t])) begin | |
| mst_r_ready_tran[t] = 1'b1; | |
| if (mst_resp.r_valid) begin | |
| automatic addr_t mst_port_offset; | |
| automatic addr_t slv_port_offset; | |
| mst_port_offset = AxiMstPortStrbWidth == 1 ? '0 : r_req_q.ar.addr[idx_width(AxiMstPortStrbWidth)-1:0]; | |
| slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : r_req_q.ar.addr[idx_width(AxiSlvPortStrbWidth)-1:0]; | |
| for (int b = 0; b < AxiSlvPortStrbWidth; b++) begin | |
| if ((b >= slv_port_offset) && | |
| (b - slv_port_offset < (1 << r_req_q.orig_ar_size)) && | |
| (b + mst_port_offset - slv_port_offset < AxiMstPortStrbWidth)) begin | |
| r_data[b] = mst_resp.r.data[8*(b + mst_port_offset - slv_port_offset) +: 8]; | |
| end | |
| end | |
| r_req_d.burst_len = r_req_q.burst_len - 1 ; | |
| r_req_d.ar.len = r_req_q.ar.len - 1 ; | |
| r_req_d.r.data = r_data ; | |
| r_req_d.r.last = (r_req_q.burst_len == 0); | |
| r_req_d.r.id = mst_resp.r.id ; | |
| r_req_d.r.user = mst_resp.r.user ; | |
| r_req_d.r.resp = axi_pkg::resp_precedence(r_req_q.r.resp, mst_resp.r.resp); | |
| case (r_req_d.ar.burst) | |
| axi_pkg::BURST_INCR: begin | |
| r_req_d.ar.addr = aligned_addr(axi_pkg::largest_addr_t'(r_req_q.ar.addr), r_req_q.ar.size) + (1 << r_req_q.ar.size); | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| r_req_d.ar.addr = r_req_q.ar.addr; | |
| end | |
| endcase | |
| if (r_req_q.burst_len == 0) begin | |
| idqueue_pop[t] = 1'b1; | |
| end | |
| case (r_state_q) | |
| R_PASSTHROUGH : begin | |
| r_req_d.r_valid = 1'b1; | |
| end | |
| R_INCR_DOWNSIZE, R_SPLIT_INCR_DOWNSIZE: begin | |
| if (r_req_q.burst_len == 0 || | |
| (aligned_addr(axi_pkg::largest_addr_t'(r_req_d.ar.addr), r_req_q.orig_ar_size) != | |
| aligned_addr(axi_pkg::largest_addr_t'(r_req_q.ar.addr), r_req_q.orig_ar_size) )) begin | |
| r_req_d.r_valid = 1'b1; | |
| end | |
| end | |
| endcase | |
| if (r_state_q == R_SPLIT_INCR_DOWNSIZE) begin | |
| if (r_req_q.ar.len == '0 && r_req_q.burst_len != '0) begin | |
| r_req_d.ar_valid = !r_req_q.injected_aw; | |
| r_req_d.ar.len = (r_req_d.burst_len <= 255) ? r_req_d.burst_len : 255; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| end | |
| if (slv_r_valid_tran[t] && slv_r_ready_tran[t]) begin | |
| if (r_req_q.burst_len == '1) begin | |
| r_state_d = R_IDLE; | |
| end | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| r_state_q <= R_IDLE; | |
| r_req_q <= '0 ; | |
| end else begin | |
| r_state_q <= r_state_d; | |
| r_req_q <= r_req_d ; | |
| end | |
| end | |
| end : gen_read_downsizer | |
| typedef enum logic [1:0] { | |
| W_IDLE , | |
| W_PASSTHROUGH , | |
| W_INCR_DOWNSIZE, | |
| W_SPLIT_INCR_DOWNSIZE | |
| } w_state_e; | |
| w_state_e w_state_d, w_state_q; | |
| logic forward_b_beat_i; | |
| logic forward_b_beat_o; | |
| logic forward_b_beat_push; | |
| logic forward_b_beat_pop; | |
| logic forward_b_beat_full; | |
| fifo_v3 #( | |
| .DATA_WIDTH (1 ), | |
| .DEPTH (AxiMaxReads), | |
| .FALL_THROUGH(1'b1 ) | |
| ) i_forward_b_beats_queue ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .flush_i (1'b0 ), | |
| .testmode_i(1'b0 ), | |
| .data_i (forward_b_beat_i ), | |
| .push_i (forward_b_beat_push ), | |
| .full_o (forward_b_beat_full ), | |
| .data_o (forward_b_beat_o ), | |
| .pop_i (forward_b_beat_pop ), | |
| .empty_o ( ), | |
| .usage_o ( ) | |
| ); | |
| mst_data_t w_data; | |
| always_comb begin | |
| inject_aw_into_ar_req = 1'b0; | |
| forward_b_beat_i = '0 ; | |
| forward_b_beat_push = 1'b0; | |
| forward_b_beat_pop = 1'b0; | |
| w_state_d = w_state_q; | |
| w_req_d = w_req_q ; | |
| mst_req.aw = w_req_q.aw ; | |
| mst_req.aw_valid = w_req_q.aw_valid; | |
| slv_resp_o.aw_ready = '0 ; | |
| mst_req_aw_err = w_req_q.aw_throw_error; | |
| mst_req.w = '0; | |
| mst_req.w_valid = '0; | |
| slv_resp_o.w_ready = '0; | |
| w_data = '0; | |
| if (mst_resp.b_valid) begin | |
| w_req_d.burst_resp = axi_pkg::resp_precedence(w_req_q.burst_resp, mst_resp.b.resp); | |
| end | |
| slv_resp_o.b = mst_resp.b ; | |
| slv_resp_o.b.resp = w_req_d.burst_resp; | |
| if (forward_b_beat_o) begin | |
| slv_resp_o.b_valid = mst_resp.b_valid ; | |
| mst_req.b_ready = slv_req_i.b_ready; | |
| if (mst_req.b_ready && mst_resp.b_valid) begin | |
| forward_b_beat_pop = 1'b1; | |
| end | |
| end else begin | |
| slv_resp_o.b_valid = 1'b0 ; | |
| mst_req.b_ready = 1'b1 ; | |
| forward_b_beat_pop = mst_resp.b_valid; | |
| end | |
| if (mst_req.aw_valid & mst_resp.aw_ready) begin | |
| w_req_d.aw_valid = 1'b0; | |
| w_req_d.aw_throw_error = 1'b0; | |
| end | |
| case (w_state_q) | |
| W_PASSTHROUGH, W_INCR_DOWNSIZE, W_SPLIT_INCR_DOWNSIZE: begin | |
| if (!w_req_q.aw_valid) begin | |
| if (slv_req_i.w_valid) begin | |
| automatic logic [idx_width(AxiMstPortStrbWidth)-1:0] mst_port_offset; | |
| automatic logic [idx_width(AxiSlvPortStrbWidth)-1:0] slv_port_offset; | |
| mst_port_offset = AxiMstPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiMstPortStrbWidth)-1:0]; | |
| slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiSlvPortStrbWidth)-1:0]; | |
| mst_req.w_valid = !(forward_b_beat_full && w_req_q.aw.len == 0); | |
| mst_req.w.last = w_req_q.aw.len == 0; | |
| mst_req.w.user = slv_req_i.w.user ; | |
| for (int b = 0; b < AxiSlvPortStrbWidth; b++) begin | |
| if ((b >= slv_port_offset) && | |
| (b - slv_port_offset < (1 << w_req_q.orig_aw_size)) && | |
| (b + mst_port_offset - slv_port_offset < AxiMstPortStrbWidth)) begin | |
| w_data[b + mst_port_offset - slv_port_offset] = slv_req_i.w.data[8*b +: 8]; | |
| mst_req.w.strb[b + mst_port_offset - slv_port_offset] = slv_req_i.w.strb[b] ; | |
| end | |
| end | |
| mst_req.w.data = w_data; | |
| end | |
| end | |
| if (mst_resp.w_ready && mst_req.w_valid) begin | |
| w_req_d.burst_len = w_req_q.burst_len - 1; | |
| w_req_d.aw.len = w_req_q.aw.len - 1 ; | |
| case (w_req_d.aw.burst) | |
| axi_pkg::BURST_INCR: begin | |
| w_req_d.aw.addr = aligned_addr(axi_pkg::largest_addr_t'(w_req_q.aw.addr), w_req_q.aw.size) + (1 << w_req_q.aw.size); | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| w_req_d.aw.addr = w_req_q.aw.addr; | |
| end | |
| endcase | |
| case (w_state_q) | |
| W_PASSTHROUGH: begin | |
| slv_resp_o.w_ready = 1'b1; | |
| end | |
| W_INCR_DOWNSIZE, W_SPLIT_INCR_DOWNSIZE: begin | |
| if (w_req_q.burst_len == 0 || | |
| (aligned_addr(axi_pkg::largest_addr_t'(w_req_d.aw.addr), w_req_q.orig_aw_size) != | |
| aligned_addr(axi_pkg::largest_addr_t'(w_req_q.aw.addr), w_req_q.orig_aw_size) )) begin | |
| slv_resp_o.w_ready = 1'b1; | |
| end | |
| end | |
| endcase | |
| if (w_state_q == W_SPLIT_INCR_DOWNSIZE) begin | |
| if (w_req_q.aw.len == '0 && w_req_q.burst_len != '0) begin | |
| w_req_d.aw_valid = 1'b1; | |
| w_req_d.aw.len = (w_req_d.burst_len <= 255) ? w_req_d.burst_len : 255; | |
| forward_b_beat_i = 1'b0; | |
| forward_b_beat_push = 1'b1; | |
| end | |
| end | |
| if (w_req_q.burst_len == 0) begin | |
| w_state_d = W_IDLE; | |
| forward_b_beat_push = 1'b1; | |
| forward_b_beat_i = 1'b1; | |
| end | |
| end | |
| end | |
| default: ; | |
| endcase | |
| if (w_state_d == W_IDLE) begin | |
| w_req_d.aw = '0 ; | |
| w_req_d.aw_valid = 1'b0 ; | |
| w_req_d.aw_throw_error = 1'b0 ; | |
| w_req_d.burst_resp = axi_pkg::RESP_EXOKAY; | |
| if (!forward_b_beat_full) begin | |
| if (slv_req_i.aw_valid && slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP]) begin | |
| inject_aw_into_ar_req = 1'b1 ; | |
| slv_resp_o.aw_ready = inject_aw_into_ar_gnt; | |
| end else begin | |
| slv_resp_o.aw_ready = 1'b1; | |
| end | |
| if (slv_req_i.aw_valid && slv_resp_o.aw_ready) begin | |
| w_state_d = W_PASSTHROUGH; | |
| w_req_d.aw = slv_req_i.aw ; | |
| w_req_d.aw_valid = 1'b1 ; | |
| w_req_d.burst_len = slv_req_i.aw.len ; | |
| w_req_d.orig_aw_len = slv_req_i.aw.len ; | |
| w_req_d.orig_aw_size = slv_req_i.aw.size ; | |
| w_req_d.orig_aw_burst = slv_req_i.aw.burst; | |
| case (slv_req_i.aw.burst) | |
| axi_pkg::BURST_INCR: begin | |
| automatic addr_t size_mask; | |
| automatic addr_t conv_ratio; | |
| automatic addr_t align_adj; | |
| size_mask = (1 << slv_req_i.aw.size) - 1 ; | |
| conv_ratio = ((1 << slv_req_i.aw.size) + AxiMstPortStrbWidth - 1) / AxiMstPortStrbWidth; | |
| align_adj = (slv_req_i.aw.addr & size_mask & ~MstPortByteMask) / AxiMstPortStrbWidth; | |
| w_req_d.burst_len = (slv_req_i.aw.len + 1) * conv_ratio - align_adj - 1 ; | |
| if (conv_ratio != 1) begin | |
| w_req_d.aw.size = AxiMstPortMaxSize; | |
| if (w_req_d.burst_len <= 255) begin | |
| w_state_d = W_INCR_DOWNSIZE ; | |
| w_req_d.aw.len = w_req_d.burst_len; | |
| end else begin | |
| w_state_d = W_SPLIT_INCR_DOWNSIZE; | |
| w_req_d.aw.len = 255 - align_adj ; | |
| end | |
| end | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| if (slv_req_i.aw.len == '0) begin | |
| automatic addr_t size_mask; | |
| automatic addr_t conv_ratio; | |
| automatic addr_t align_adj; | |
| size_mask = (1 << slv_req_i.aw.size) - 1 ; | |
| conv_ratio = ((1 << slv_req_i.aw.size) + AxiMstPortStrbWidth - 1) / AxiMstPortStrbWidth; | |
| align_adj = (slv_req_i.aw.addr & size_mask & ~MstPortByteMask) / AxiMstPortStrbWidth; | |
| w_req_d.burst_len = (conv_ratio >= align_adj + 1) ? (conv_ratio - align_adj - 1) : 0 ; | |
| if (conv_ratio != 1) begin | |
| w_state_d = W_INCR_DOWNSIZE ; | |
| w_req_d.aw.len = w_req_d.burst_len ; | |
| w_req_d.aw.size = AxiMstPortMaxSize ; | |
| w_req_d.aw.burst = axi_pkg::BURST_INCR; | |
| end | |
| end else begin | |
| w_req_d.aw_throw_error = 1'b1; | |
| end | |
| end | |
| axi_pkg::BURST_WRAP: begin | |
| w_state_d = W_PASSTHROUGH; | |
| w_req_d.aw_throw_error = 1'b1 ; | |
| end | |
| default: ; | |
| endcase | |
| end | |
| end | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| w_state_q <= W_IDLE; | |
| w_req_q <= '0 ; | |
| end else begin | |
| w_state_q <= w_state_d; | |
| w_req_q <= w_req_d ; | |
| end | |
| end | |
| endmodule : axi_dw_downsizer | |
| `begin_keywords "1800-2023" | |
| module axi_dw_upsizer #( | |
| parameter int unsigned AxiMaxReads = 1 , | |
| parameter int unsigned AxiSlvPortDataWidth = 8 , | |
| parameter int unsigned AxiMstPortDataWidth = 8 , | |
| parameter int unsigned AxiAddrWidth = 1 , | |
| parameter int unsigned AxiIdWidth = 1 , | |
| parameter type aw_chan_t = logic, | |
| parameter type mst_w_chan_t = logic, | |
| parameter type slv_w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type mst_r_chan_t = logic, | |
| parameter type slv_r_chan_t = logic, | |
| parameter type axi_mst_req_t = logic, | |
| parameter type axi_mst_resp_t = logic, | |
| parameter type axi_slv_req_t = logic, | |
| parameter type axi_slv_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_slv_req_t slv_req_i, | |
| output axi_slv_resp_t slv_resp_o, | |
| output axi_mst_req_t mst_req_o, | |
| input axi_mst_resp_t mst_resp_i | |
| ); | |
| import axi_pkg::aligned_addr; | |
| import axi_pkg::beat_addr ; | |
| import axi_pkg::modifiable ; | |
| import cf_math_pkg::idx_width; | |
| localparam TranIdWidth = AxiMaxReads > 1 ? $clog2(AxiMaxReads) : 1; | |
| typedef logic [TranIdWidth-1:0] tran_id_t; | |
| localparam AxiSlvPortStrbWidth = AxiSlvPortDataWidth / 8; | |
| localparam AxiMstPortStrbWidth = AxiMstPortDataWidth / 8; | |
| localparam AxiSlvPortMaxSize = $clog2(AxiSlvPortStrbWidth); | |
| localparam AxiMstPortMaxSize = $clog2(AxiMstPortStrbWidth); | |
| typedef logic [AxiMstPortStrbWidth-1:0][7:0] mst_data_t; | |
| typedef logic [AxiSlvPortStrbWidth-1:0][7:0] slv_data_t; | |
| typedef logic [AxiAddrWidth-1:0] addr_t; | |
| typedef logic [AxiIdWidth-1:0] id_t; | |
| typedef logic [$clog2(AxiMstPortStrbWidth/AxiSlvPortStrbWidth) + 7:0] burst_len_t; | |
| axi_mst_req_t mst_req; | |
| axi_mst_resp_t mst_resp; | |
| slv_r_chan_t [AxiMaxReads-1:0] slv_r_tran; | |
| logic [AxiMaxReads-1:0] slv_r_valid_tran; | |
| logic [AxiMaxReads-1:0] slv_r_ready_tran; | |
| rr_arb_tree #( | |
| .NumIn (AxiMaxReads ), | |
| .DataType (slv_r_chan_t), | |
| .AxiVldRdy(1'b1 ), | |
| .ExtPrio (1'b0 ), | |
| .LockIn (1'b1 ) | |
| ) i_slv_r_arb ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .flush_i(1'b0 ), | |
| .rr_i ('0 ), | |
| .req_i (slv_r_valid_tran ), | |
| .gnt_o (slv_r_ready_tran ), | |
| .data_i (slv_r_tran ), | |
| .gnt_i (slv_req_i.r_ready ), | |
| .req_o (slv_resp_o.r_valid), | |
| .data_o (slv_resp_o.r ), | |
| .idx_o ( ) | |
| ); | |
| logic [AxiMaxReads-1:0] mst_r_ready_tran; | |
| assign mst_req.r_ready = |mst_r_ready_tran; | |
| id_t arb_slv_ar_id; | |
| logic arb_slv_ar_req; | |
| logic arb_slv_ar_gnt; | |
| logic [AxiMaxReads-1:0] arb_slv_ar_gnt_tran; | |
| logic inject_aw_into_ar; | |
| logic inject_aw_into_ar_req; | |
| logic inject_aw_into_ar_gnt; | |
| assign arb_slv_ar_gnt = |arb_slv_ar_gnt_tran; | |
| rr_arb_tree #( | |
| .NumIn (2 ), | |
| .DataWidth (AxiIdWidth), | |
| .ExtPrio (1'b0 ), | |
| .AxiVldRdy (1'b1 ), | |
| .LockIn (1'b0 ) | |
| ) i_slv_ar_arb ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .flush_i(1'b0 ), | |
| .rr_i ('0 ), | |
| .req_i ({inject_aw_into_ar_req, slv_req_i.ar_valid} ), | |
| .gnt_o ({inject_aw_into_ar_gnt, slv_resp_o.ar_ready}), | |
| .data_i ({slv_req_i.aw.id, slv_req_i.ar.id} ), | |
| .req_o (arb_slv_ar_req ), | |
| .gnt_i (arb_slv_ar_gnt ), | |
| .data_o (arb_slv_ar_id ), | |
| .idx_o (inject_aw_into_ar ) | |
| ); | |
| ar_chan_t [AxiMaxReads-1:0] mst_ar_tran; | |
| id_t [AxiMaxReads-1:0] mst_ar_id; | |
| logic [AxiMaxReads-1:0] mst_ar_valid_tran; | |
| logic [AxiMaxReads-1:0] mst_ar_ready_tran; | |
| tran_id_t mst_req_idx; | |
| rr_arb_tree #( | |
| .NumIn (AxiMaxReads), | |
| .DataType (ar_chan_t ), | |
| .AxiVldRdy(1'b1 ), | |
| .ExtPrio (1'b0 ), | |
| .LockIn (1'b1 ) | |
| ) i_mst_ar_arb ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .flush_i(1'b0 ), | |
| .rr_i ('0 ), | |
| .req_i (mst_ar_valid_tran), | |
| .gnt_o (mst_ar_ready_tran), | |
| .data_i (mst_ar_tran ), | |
| .gnt_i (mst_resp.ar_ready), | |
| .req_o (mst_req.ar_valid ), | |
| .data_o (mst_req.ar ), | |
| .idx_o (mst_req_idx ) | |
| ); | |
| axi_mst_req_t axi_err_req; | |
| axi_mst_resp_t axi_err_resp; | |
| axi_err_slv #( | |
| .AxiIdWidth(AxiIdWidth ), | |
| .Resp (axi_pkg::RESP_SLVERR), | |
| .axi_req_t (axi_mst_req_t ), | |
| .axi_resp_t(axi_mst_resp_t ) | |
| ) i_axi_err_slv ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .test_i (1'b0 ), | |
| .slv_req_i (axi_err_req ), | |
| .slv_resp_o(axi_err_resp) | |
| ); | |
| logic [AxiMaxReads-1:0] mst_req_ar_err; | |
| logic mst_req_aw_err; | |
| axi_demux #( | |
| .AxiIdWidth (AxiIdWidth ), | |
| .AxiLookBits(AxiIdWidth ), | |
| .aw_chan_t (aw_chan_t ), | |
| .w_chan_t (mst_w_chan_t ), | |
| .b_chan_t (b_chan_t ), | |
| .ar_chan_t (ar_chan_t ), | |
| .r_chan_t (mst_r_chan_t ), | |
| .axi_req_t (axi_mst_req_t ), | |
| .axi_resp_t (axi_mst_resp_t), | |
| .NoMstPorts (2 ), | |
| .MaxTrans (AxiMaxReads ), | |
| .SpillAw (1'b1 ) | |
| ) i_axi_demux ( | |
| .clk_i (clk_i ), | |
| .rst_ni (rst_ni ), | |
| .test_i (1'b0 ), | |
| .mst_reqs_o ({axi_err_req, mst_req_o} ), | |
| .mst_resps_i ({axi_err_resp, mst_resp_i} ), | |
| .slv_ar_select_i(mst_req_ar_err[mst_req_idx]), | |
| .slv_aw_select_i(mst_req_aw_err ), | |
| .slv_req_i (mst_req ), | |
| .slv_resp_o (mst_resp ) | |
| ); | |
| typedef enum logic [1:0] { | |
| R_IDLE , | |
| R_INJECT_AW , | |
| R_PASSTHROUGH, | |
| R_INCR_UPSIZE | |
| } r_state_e; | |
| typedef struct packed { | |
| aw_chan_t aw ; | |
| logic aw_valid ; | |
| logic aw_throw_error ; | |
| mst_w_chan_t w ; | |
| logic w_valid ; | |
| axi_pkg::len_t burst_len ; | |
| axi_pkg::size_t orig_aw_size; | |
| } w_req_t; | |
| w_req_t w_req_d, w_req_q; | |
| logic [AxiMaxReads-1:0] idle_read_upsizer; | |
| tran_id_t idx_ar_upsizer ; | |
| tran_id_t idx_idle_upsizer; | |
| lzc #( | |
| .WIDTH(AxiMaxReads) | |
| ) i_idle_lzc ( | |
| .in_i (idle_read_upsizer), | |
| .cnt_o (idx_idle_upsizer ), | |
| .empty_o( ) | |
| ); | |
| logic [AxiMaxReads-1:0] id_clash_upsizer; | |
| tran_id_t idx_id_clash_upsizer ; | |
| for (genvar t = 0; t < AxiMaxReads; t++) begin: gen_id_clash | |
| assign id_clash_upsizer[t] = arb_slv_ar_id == mst_ar_id[t] && !idle_read_upsizer[t]; | |
| end | |
| onehot_to_bin #( | |
| .ONEHOT_WIDTH(AxiMaxReads) | |
| ) i_id_clash_onehot_to_bin ( | |
| .onehot(id_clash_upsizer ), | |
| .bin (idx_id_clash_upsizer) | |
| ); | |
| assign idx_ar_upsizer = (|id_clash_upsizer) ? idx_id_clash_upsizer : idx_idle_upsizer; | |
| logic r_upsizer_valid; | |
| tran_id_t idx_r_upsizer; | |
| logic [AxiMaxReads-1:0] rid_upsizer_match; | |
| assign r_upsizer_valid = |rid_upsizer_match; | |
| for (genvar t = 0; t < AxiMaxReads; t++) begin: gen_rid_match | |
| assign rid_upsizer_match[t] = (mst_resp.r.id == mst_ar_id[t]) && !idle_read_upsizer[t]; | |
| end | |
| onehot_to_bin #( | |
| .ONEHOT_WIDTH(AxiMaxReads) | |
| ) i_rid_upsizer_lzc ( | |
| .onehot(rid_upsizer_match), | |
| .bin (idx_r_upsizer ) | |
| ); | |
| typedef struct packed { | |
| ar_chan_t ar ; | |
| logic ar_valid ; | |
| logic ar_throw_error ; | |
| axi_pkg::len_t burst_len ; | |
| axi_pkg::size_t orig_ar_size; | |
| } r_req_t; | |
| for (genvar t = 0; unsigned'(t) < AxiMaxReads; t++) begin: gen_read_upsizer | |
| r_state_e r_state_d, r_state_q; | |
| r_req_t r_req_d , r_req_q ; | |
| assign idle_read_upsizer[t] = (r_state_q == R_IDLE) || (r_state_q == R_INJECT_AW); | |
| slv_data_t r_data; | |
| always_comb begin | |
| r_state_d = r_state_q; | |
| r_req_d = r_req_q ; | |
| mst_ar_tran[t] = r_req_q.ar ; | |
| mst_ar_id[t] = r_req_q.ar.id ; | |
| mst_ar_valid_tran[t] = r_req_q.ar_valid; | |
| mst_req_ar_err[t] = r_req_q.ar_throw_error; | |
| slv_r_tran[t] = '0 ; | |
| slv_r_tran[t].id = mst_resp.r.id ; | |
| slv_r_tran[t].resp = mst_resp.r.resp; | |
| slv_r_tran[t].user = mst_resp.r.user; | |
| arb_slv_ar_gnt_tran[t] = 1'b0; | |
| mst_r_ready_tran[t] = 1'b0; | |
| slv_r_valid_tran[t] = 1'b0; | |
| if (mst_ar_valid_tran[t] && mst_ar_ready_tran[t]) begin | |
| r_req_d.ar_valid = 1'b0; | |
| r_req_d.ar_throw_error = 1'b0; | |
| end | |
| r_data = '0; | |
| unique case (r_state_q) | |
| R_IDLE : begin | |
| r_req_d.ar = '0; | |
| if (arb_slv_ar_req && (idx_ar_upsizer == t)) begin | |
| arb_slv_ar_gnt_tran[t] = 1'b1; | |
| if (inject_aw_into_ar) begin | |
| r_state_d = R_INJECT_AW; | |
| end else begin | |
| r_state_d = R_PASSTHROUGH; | |
| r_req_d.ar = slv_req_i.ar ; | |
| r_req_d.ar_valid = 1'b1 ; | |
| r_req_d.burst_len = slv_req_i.ar.len ; | |
| r_req_d.orig_ar_size = slv_req_i.ar.size; | |
| unique case (r_req_d.ar.burst) | |
| axi_pkg::BURST_INCR: begin | |
| if (modifiable(r_req_d.ar.cache)) begin | |
| if (r_req_d.ar.len != '0) begin | |
| automatic addr_t start_addr; | |
| automatic addr_t end_addr; | |
| start_addr = aligned_addr(r_req_d.ar.addr, AxiMstPortMaxSize); | |
| end_addr = aligned_addr(beat_addr(r_req_d.ar.addr, | |
| r_req_d.orig_ar_size, r_req_d.burst_len, r_req_d.ar.burst, | |
| r_req_d.burst_len), AxiMstPortMaxSize); | |
| r_req_d.ar.len = (end_addr - start_addr) >> AxiMstPortMaxSize; | |
| r_req_d.ar.size = AxiMstPortMaxSize ; | |
| r_state_d = R_INCR_UPSIZE ; | |
| end | |
| end | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| r_state_d = R_PASSTHROUGH; | |
| end | |
| axi_pkg::BURST_WRAP: begin | |
| r_state_d = R_PASSTHROUGH; | |
| r_req_d.ar_throw_error = 1'b1 ; | |
| if (r_req_d.ar.len == '0) | |
| r_req_d.ar_throw_error = 1'b0; | |
| end | |
| default: ; | |
| endcase | |
| end | |
| end | |
| end | |
| R_INJECT_AW : begin | |
| r_req_d.ar.id = w_req_q.aw.id ; | |
| r_req_d.ar.addr = w_req_q.aw.addr ; | |
| r_req_d.ar.size = w_req_q.orig_aw_size; | |
| r_req_d.ar.burst = w_req_q.aw.burst ; | |
| r_req_d.ar.len = w_req_q.burst_len ; | |
| r_req_d.ar.lock = w_req_q.aw.lock ; | |
| r_req_d.ar.cache = w_req_q.aw.cache ; | |
| r_req_d.ar.prot = w_req_q.aw.prot ; | |
| r_req_d.ar.qos = w_req_q.aw.qos ; | |
| r_req_d.ar.region = w_req_q.aw.region ; | |
| r_req_d.ar.user = w_req_q.aw.user ; | |
| r_req_d.ar_valid = 1'b0 ; | |
| r_req_d.burst_len = w_req_q.burst_len ; | |
| r_req_d.orig_ar_size = w_req_q.orig_aw_size; | |
| r_state_d = R_PASSTHROUGH; | |
| unique case (r_req_d.ar.burst) | |
| axi_pkg::BURST_INCR: begin | |
| if (modifiable(r_req_d.ar.cache)) begin | |
| if (r_req_d.ar.len != '0) begin | |
| automatic addr_t start_addr; | |
| automatic addr_t end_addr; | |
| start_addr = aligned_addr(r_req_d.ar.addr, AxiMstPortMaxSize); | |
| end_addr = aligned_addr(beat_addr(r_req_d.ar.addr, | |
| r_req_d.orig_ar_size, r_req_d.burst_len, r_req_d.ar.burst, | |
| r_req_d.burst_len), AxiMstPortMaxSize); | |
| r_req_d.ar.len = (end_addr - start_addr) >> AxiMstPortMaxSize; | |
| r_req_d.ar.size = AxiMstPortMaxSize ; | |
| r_state_d = R_INCR_UPSIZE ; | |
| end | |
| end | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| r_state_d = R_PASSTHROUGH; | |
| end | |
| axi_pkg::BURST_WRAP: begin | |
| r_state_d = R_PASSTHROUGH; | |
| r_req_d.ar_throw_error = 1'b1 ; | |
| if (r_req_d.ar.len == '0) | |
| r_req_d.ar_throw_error = 1'b0; | |
| end | |
| default: ; | |
| endcase | |
| end | |
| R_PASSTHROUGH, R_INCR_UPSIZE: begin | |
| if (!r_req_q.ar_valid) | |
| if (mst_resp.r_valid && (idx_r_upsizer == t) && r_upsizer_valid) begin | |
| automatic logic [idx_width(AxiMstPortStrbWidth)-1:0] mst_port_offset; | |
| automatic logic [idx_width(AxiSlvPortStrbWidth)-1:0] slv_port_offset; | |
| mst_port_offset = AxiMstPortStrbWidth == 1 ? '0 : r_req_q.ar.addr[idx_width(AxiMstPortStrbWidth)-1:0]; | |
| slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : r_req_q.ar.addr[idx_width(AxiSlvPortStrbWidth)-1:0]; | |
| slv_r_valid_tran[t] = 1'b1 ; | |
| slv_r_tran[t].last = mst_resp.r.last && (r_req_q.burst_len == 0); | |
| for (int b = 0; b < AxiMstPortStrbWidth; b++) begin | |
| if ((b >= mst_port_offset) && | |
| (b - mst_port_offset < (1 << r_req_q.orig_ar_size)) && | |
| (b + slv_port_offset - mst_port_offset < AxiSlvPortStrbWidth)) begin | |
| r_data[b + slv_port_offset - mst_port_offset] = mst_resp.r.data[8*b +: 8]; | |
| end | |
| end | |
| slv_r_tran[t].data = r_data; | |
| if (slv_r_ready_tran[t]) begin | |
| r_req_d.burst_len = r_req_q.burst_len - 1; | |
| unique case (r_req_q.ar.burst) | |
| axi_pkg::BURST_INCR: begin | |
| r_req_d.ar.addr = aligned_addr(r_req_q.ar.addr, r_req_q.orig_ar_size) + (1 << r_req_q.orig_ar_size); | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| r_req_d.ar.addr = r_req_q.ar.addr; | |
| end | |
| default: ; | |
| endcase | |
| unique case (r_state_q) | |
| R_PASSTHROUGH: | |
| mst_r_ready_tran[t] = 1'b1; | |
| R_INCR_UPSIZE: | |
| if (r_req_q.burst_len == 0 || (aligned_addr(r_req_d.ar.addr, AxiMstPortMaxSize) != aligned_addr(r_req_q.ar.addr, AxiMstPortMaxSize))) | |
| mst_r_ready_tran[t] = 1'b1; | |
| default: ; | |
| endcase | |
| if (r_req_q.burst_len == '0) | |
| r_state_d = R_IDLE; | |
| end | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| r_state_q <= R_IDLE; | |
| r_req_q <= '0 ; | |
| end else begin | |
| r_state_q <= r_state_d; | |
| r_req_q <= r_req_d ; | |
| end | |
| end | |
| end : gen_read_upsizer | |
| typedef enum logic [1:0] { | |
| W_IDLE , | |
| W_PASSTHROUGH, | |
| W_INCR_UPSIZE | |
| } w_state_e; | |
| w_state_e w_state_d, w_state_q; | |
| mst_data_t w_data; | |
| always_comb begin | |
| inject_aw_into_ar_req = 1'b0; | |
| w_state_d = w_state_q; | |
| w_req_d = w_req_q ; | |
| mst_req.aw = w_req_q.aw ; | |
| mst_req.aw_valid = w_req_q.aw_valid; | |
| slv_resp_o.aw_ready = '0 ; | |
| mst_req_aw_err = w_req_q.aw_throw_error; | |
| mst_req.w = w_req_q.w ; | |
| mst_req.w_valid = w_req_q.w_valid; | |
| slv_resp_o.w_ready = '0 ; | |
| w_data = w_req_q.w.data; | |
| slv_resp_o.b = mst_resp.b ; | |
| slv_resp_o.b_valid = mst_resp.b_valid ; | |
| mst_req.b_ready = slv_req_i.b_ready; | |
| if (mst_req.aw_valid && mst_resp.aw_ready) begin | |
| w_req_d.aw_valid = 1'b0; | |
| w_req_d.aw_throw_error = 1'b0; | |
| end | |
| unique case (w_state_q) | |
| W_PASSTHROUGH, W_INCR_UPSIZE: begin | |
| if (mst_req.w_valid && mst_resp.w_ready) begin | |
| w_data = '0 ; | |
| w_req_d.w = '0 ; | |
| w_req_d.w_valid = 1'b0; | |
| end | |
| if (!w_req_q.aw_valid) begin | |
| slv_resp_o.w_ready = ~mst_req.w_valid || mst_resp.w_ready; | |
| if (slv_req_i.w_valid && slv_resp_o.w_ready) begin | |
| automatic addr_t mst_port_offset; | |
| automatic addr_t slv_port_offset; | |
| mst_port_offset = AxiMstPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiMstPortStrbWidth)-1:0]; | |
| slv_port_offset = AxiSlvPortStrbWidth == 1 ? '0 : w_req_q.aw.addr[idx_width(AxiSlvPortStrbWidth)-1:0]; | |
| for (int b = 0; b < AxiMstPortStrbWidth; b++) | |
| if ((b >= mst_port_offset) && | |
| (b - mst_port_offset < (1 << w_req_q.orig_aw_size)) && | |
| (b + slv_port_offset - mst_port_offset < AxiSlvPortStrbWidth)) begin | |
| w_data[b] = slv_req_i.w.data[8*(b + slv_port_offset - mst_port_offset) +: 8]; | |
| w_req_d.w.strb[b] = slv_req_i.w.strb[b + slv_port_offset - mst_port_offset] ; | |
| end | |
| w_req_d.burst_len = w_req_q.burst_len - 1 ; | |
| w_req_d.w.data = w_data ; | |
| w_req_d.w.last = (w_req_q.burst_len == 0); | |
| w_req_d.w.user = slv_req_i.w.user ; | |
| unique case (w_req_q.aw.burst) | |
| axi_pkg::BURST_INCR: begin | |
| w_req_d.aw.addr = aligned_addr(w_req_q.aw.addr, w_req_q.orig_aw_size) + (1 << w_req_q.orig_aw_size); | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| w_req_d.aw.addr = w_req_q.aw.addr; | |
| end | |
| default: ; | |
| endcase | |
| unique case (w_state_q) | |
| W_PASSTHROUGH: | |
| w_req_d.w_valid = 1'b1; | |
| W_INCR_UPSIZE: | |
| if (w_req_q.burst_len == 0 || (aligned_addr(w_req_d.aw.addr, AxiMstPortMaxSize) != aligned_addr(w_req_q.aw.addr, AxiMstPortMaxSize))) | |
| w_req_d.w_valid = 1'b1; | |
| default: ; | |
| endcase | |
| end | |
| end | |
| if (mst_req.w_valid && mst_resp.w_ready) | |
| if (w_req_q.burst_len == '1) begin | |
| slv_resp_o.w_ready = 1'b0 ; | |
| w_state_d = W_IDLE; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| if (w_state_d == W_IDLE) begin | |
| w_req_d.aw = '0 ; | |
| w_req_d.aw_valid = 1'b0; | |
| w_req_d.aw_throw_error = 1'b0; | |
| w_req_d.w = '0 ; | |
| w_req_d.w_valid = 1'b0; | |
| if (slv_req_i.aw_valid && slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP]) begin | |
| inject_aw_into_ar_req = 1'b1 ; | |
| slv_resp_o.aw_ready = inject_aw_into_ar_gnt; | |
| end else begin | |
| slv_resp_o.aw_ready = 1'b1; | |
| end | |
| if (slv_req_i.aw_valid & slv_resp_o.aw_ready) begin | |
| w_state_d = W_PASSTHROUGH; | |
| w_req_d.aw = slv_req_i.aw; | |
| w_req_d.aw_valid = 1'b1 ; | |
| w_req_d.burst_len = slv_req_i.aw.len ; | |
| w_req_d.orig_aw_size = slv_req_i.aw.size; | |
| unique case (slv_req_i.aw.burst) | |
| axi_pkg::BURST_INCR: begin | |
| if (modifiable(slv_req_i.aw.cache)) | |
| if (slv_req_i.aw.len != '0) begin | |
| automatic addr_t start_addr; | |
| automatic addr_t end_addr; | |
| start_addr = aligned_addr(slv_req_i.aw.addr, AxiMstPortMaxSize); | |
| end_addr = aligned_addr(beat_addr(slv_req_i.aw.addr, | |
| slv_req_i.aw.size, slv_req_i.aw.len, slv_req_i.aw.burst, slv_req_i.aw.len), | |
| AxiMstPortMaxSize); | |
| w_req_d.aw.len = (end_addr - start_addr) >> AxiMstPortMaxSize; | |
| w_req_d.aw.size = AxiMstPortMaxSize ; | |
| w_state_d = W_INCR_UPSIZE ; | |
| end | |
| end | |
| axi_pkg::BURST_FIXED: begin | |
| w_state_d = W_PASSTHROUGH; | |
| end | |
| axi_pkg::BURST_WRAP: begin | |
| w_state_d = W_PASSTHROUGH; | |
| w_req_d.aw_throw_error = 1'b1 ; | |
| if (slv_req_i.aw.len == '0) | |
| w_req_d.aw_throw_error = 1'b0; | |
| end | |
| default: ; | |
| endcase | |
| end | |
| end | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| w_state_q <= W_IDLE; | |
| w_req_q <= '0 ; | |
| end else begin | |
| w_state_q <= w_state_d; | |
| w_req_q <= w_req_d ; | |
| end | |
| end | |
| endmodule : axi_dw_upsizer | |
| `begin_keywords "1800-2023" | |
| module axi_fifo #( | |
| parameter int unsigned Depth = 32'd1, | |
| parameter bit FallThrough = 1'b0, | |
| parameter type aw_chan_t = logic, | |
| parameter type w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| if (Depth == '0) begin : gen_no_fifo | |
| assign mst_req_o = slv_req_i; | |
| assign slv_resp_o = mst_resp_i; | |
| end else begin : gen_axi_fifo | |
| logic aw_fifo_empty, ar_fifo_empty, w_fifo_empty, r_fifo_empty, b_fifo_empty; | |
| logic aw_fifo_full, ar_fifo_full, w_fifo_full, r_fifo_full, b_fifo_full; | |
| assign mst_req_o.aw_valid = ~aw_fifo_empty; | |
| assign mst_req_o.ar_valid = ~ar_fifo_empty; | |
| assign mst_req_o.w_valid = ~w_fifo_empty; | |
| assign slv_resp_o.r_valid = ~r_fifo_empty; | |
| assign slv_resp_o.b_valid = ~b_fifo_empty; | |
| assign slv_resp_o.aw_ready = ~aw_fifo_full; | |
| assign slv_resp_o.ar_ready = ~ar_fifo_full; | |
| assign slv_resp_o.w_ready = ~w_fifo_full; | |
| assign mst_req_o.r_ready = ~r_fifo_full; | |
| assign mst_req_o.b_ready = ~b_fifo_full; | |
| fifo_v3 #( | |
| .dtype(aw_chan_t), | |
| .DEPTH(Depth), | |
| .FALL_THROUGH(FallThrough) | |
| ) i_aw_fifo ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i (1'b0), | |
| .testmode_i(test_i), | |
| .full_o (aw_fifo_full), | |
| .empty_o (aw_fifo_empty), | |
| .usage_o (), | |
| .data_i (slv_req_i.aw), | |
| .push_i (slv_req_i.aw_valid && slv_resp_o.aw_ready), | |
| .data_o (mst_req_o.aw), | |
| .pop_i (mst_req_o.aw_valid && mst_resp_i.aw_ready) | |
| ); | |
| fifo_v3 #( | |
| .dtype(ar_chan_t), | |
| .DEPTH(Depth), | |
| .FALL_THROUGH(FallThrough) | |
| ) i_ar_fifo ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i (1'b0), | |
| .testmode_i(test_i), | |
| .full_o (ar_fifo_full), | |
| .empty_o (ar_fifo_empty), | |
| .usage_o (), | |
| .data_i (slv_req_i.ar), | |
| .push_i (slv_req_i.ar_valid && slv_resp_o.ar_ready), | |
| .data_o (mst_req_o.ar), | |
| .pop_i (mst_req_o.ar_valid && mst_resp_i.ar_ready) | |
| ); | |
| fifo_v3 #( | |
| .dtype(w_chan_t), | |
| .DEPTH(Depth), | |
| .FALL_THROUGH(FallThrough) | |
| ) i_w_fifo ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i (1'b0), | |
| .testmode_i(test_i), | |
| .full_o (w_fifo_full), | |
| .empty_o (w_fifo_empty), | |
| .usage_o (), | |
| .data_i (slv_req_i.w), | |
| .push_i (slv_req_i.w_valid && slv_resp_o.w_ready), | |
| .data_o (mst_req_o.w), | |
| .pop_i (mst_req_o.w_valid && mst_resp_i.w_ready) | |
| ); | |
| fifo_v3 #( | |
| .dtype(r_chan_t), | |
| .DEPTH(Depth), | |
| .FALL_THROUGH(FallThrough) | |
| ) i_r_fifo ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i (1'b0), | |
| .testmode_i(test_i), | |
| .full_o (r_fifo_full), | |
| .empty_o (r_fifo_empty), | |
| .usage_o (), | |
| .data_i (mst_resp_i.r), | |
| .push_i (mst_resp_i.r_valid && mst_req_o.r_ready), | |
| .data_o (slv_resp_o.r), | |
| .pop_i (slv_resp_o.r_valid && slv_req_i.r_ready) | |
| ); | |
| fifo_v3 #( | |
| .dtype(b_chan_t), | |
| .DEPTH(Depth), | |
| .FALL_THROUGH(FallThrough) | |
| ) i_b_fifo ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i (1'b0), | |
| .testmode_i(test_i), | |
| .full_o (b_fifo_full), | |
| .empty_o (b_fifo_empty), | |
| .usage_o (), | |
| .data_i (mst_resp_i.b), | |
| .push_i (mst_resp_i.b_valid && mst_req_o.b_ready), | |
| .data_o (slv_resp_o.b), | |
| .pop_i (slv_resp_o.b_valid && slv_req_i.b_ready) | |
| ); | |
| end | |
| endmodule | |
| module axi_fifo_intf #( | |
| parameter int unsigned ADDR_WIDTH = 0, | |
| parameter int unsigned DATA_WIDTH = 0, | |
| parameter int unsigned ID_WIDTH = 0, | |
| parameter int unsigned USER_WIDTH = 0, | |
| parameter int unsigned DEPTH = 0, | |
| parameter int unsigned FALL_THROUGH = 0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| AXI_BUS.Slave slv, | |
| AXI_BUS.Master mst | |
| ); | |
| typedef logic [ID_WIDTH-1:0] id_t; | |
| typedef logic [ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [DATA_WIDTH-1:0] data_t; | |
| typedef logic [DATA_WIDTH/8-1:0] strb_t; | |
| typedef logic [USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| b_chan_t b; | |
| logic r_valid; | |
| r_chan_t r; | |
| } axi_resp_t; | |
| axi_req_t slv_req, mst_req; | |
| axi_resp_t slv_resp, mst_resp; | |
| assign slv_req.aw.id = slv.aw_id; | |
| assign slv_req.aw.addr = slv.aw_addr; | |
| assign slv_req.aw.len = slv.aw_len; | |
| assign slv_req.aw.size = slv.aw_size; | |
| assign slv_req.aw.burst = slv.aw_burst; | |
| assign slv_req.aw.lock = slv.aw_lock; | |
| assign slv_req.aw.cache = slv.aw_cache; | |
| assign slv_req.aw.prot = slv.aw_prot; | |
| assign slv_req.aw.qos = slv.aw_qos; | |
| assign slv_req.aw.region = slv.aw_region; | |
| assign slv_req.aw.atop = slv.aw_atop; | |
| assign slv_req.aw.user = slv.aw_user; | |
| assign slv_req.aw_valid = slv.aw_valid; | |
| assign slv_req.w.data = slv.w_data; | |
| assign slv_req.w.strb = slv.w_strb; | |
| assign slv_req.w.last = slv.w_last; | |
| assign slv_req.w.user = slv.w_user; | |
| assign slv_req.w_valid = slv.w_valid; | |
| assign slv_req.b_ready = slv.b_ready; | |
| assign slv_req.ar.id = slv.ar_id; | |
| assign slv_req.ar.addr = slv.ar_addr; | |
| assign slv_req.ar.len = slv.ar_len; | |
| assign slv_req.ar.size = slv.ar_size; | |
| assign slv_req.ar.burst = slv.ar_burst; | |
| assign slv_req.ar.lock = slv.ar_lock; | |
| assign slv_req.ar.cache = slv.ar_cache; | |
| assign slv_req.ar.prot = slv.ar_prot; | |
| assign slv_req.ar.qos = slv.ar_qos; | |
| assign slv_req.ar.region = slv.ar_region; | |
| assign slv_req.ar.user = slv.ar_user; | |
| assign slv_req.ar_valid = slv.ar_valid; | |
| assign slv_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = slv_resp.aw_ready; | |
| assign slv.ar_ready = slv_resp.ar_ready; | |
| assign slv.w_ready = slv_resp.w_ready; | |
| assign slv.b_valid = slv_resp.b_valid; | |
| assign slv.b_id = slv_resp.b.id; | |
| assign slv.b_resp = slv_resp.b.resp; | |
| assign slv.b_user = slv_resp.b.user; | |
| assign slv.r_valid = slv_resp.r_valid; | |
| assign slv.r_id = slv_resp.r.id; | |
| assign slv.r_data = slv_resp.r.data; | |
| assign slv.r_resp = slv_resp.r.resp; | |
| assign slv.r_last = slv_resp.r.last; | |
| assign slv.r_user = slv_resp.r.user; | |
| assign mst.aw_id = mst_req.aw.id; | |
| assign mst.aw_addr = mst_req.aw.addr; | |
| assign mst.aw_len = mst_req.aw.len; | |
| assign mst.aw_size = mst_req.aw.size; | |
| assign mst.aw_burst = mst_req.aw.burst; | |
| assign mst.aw_lock = mst_req.aw.lock; | |
| assign mst.aw_cache = mst_req.aw.cache; | |
| assign mst.aw_prot = mst_req.aw.prot; | |
| assign mst.aw_qos = mst_req.aw.qos; | |
| assign mst.aw_region = mst_req.aw.region; | |
| assign mst.aw_atop = mst_req.aw.atop; | |
| assign mst.aw_user = mst_req.aw.user; | |
| assign mst.aw_valid = mst_req.aw_valid; | |
| assign mst.w_data = mst_req.w.data; | |
| assign mst.w_strb = mst_req.w.strb; | |
| assign mst.w_last = mst_req.w.last; | |
| assign mst.w_user = mst_req.w.user; | |
| assign mst.w_valid = mst_req.w_valid; | |
| assign mst.b_ready = mst_req.b_ready; | |
| assign mst.ar_id = mst_req.ar.id; | |
| assign mst.ar_addr = mst_req.ar.addr; | |
| assign mst.ar_len = mst_req.ar.len; | |
| assign mst.ar_size = mst_req.ar.size; | |
| assign mst.ar_burst = mst_req.ar.burst; | |
| assign mst.ar_lock = mst_req.ar.lock; | |
| assign mst.ar_cache = mst_req.ar.cache; | |
| assign mst.ar_prot = mst_req.ar.prot; | |
| assign mst.ar_qos = mst_req.ar.qos; | |
| assign mst.ar_region = mst_req.ar.region; | |
| assign mst.ar_user = mst_req.ar.user; | |
| assign mst.ar_valid = mst_req.ar_valid; | |
| assign mst.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = mst.aw_ready; | |
| assign mst_resp.ar_ready = mst.ar_ready; | |
| assign mst_resp.w_ready = mst.w_ready; | |
| assign mst_resp.b_valid = mst.b_valid; | |
| assign mst_resp.b.id = mst.b_id; | |
| assign mst_resp.b.resp = mst.b_resp; | |
| assign mst_resp.b.user = mst.b_user; | |
| assign mst_resp.r_valid = mst.r_valid; | |
| assign mst_resp.r.id = mst.r_id; | |
| assign mst_resp.r.data = mst.r_data; | |
| assign mst_resp.r.resp = mst.r_resp; | |
| assign mst_resp.r.last = mst.r_last; | |
| assign mst_resp.r.user = mst.r_user; | |
| axi_fifo #( | |
| .Depth (DEPTH), | |
| .FallThrough(FALL_THROUGH), | |
| .aw_chan_t (aw_chan_t), | |
| .w_chan_t (w_chan_t), | |
| .b_chan_t (b_chan_t), | |
| .ar_chan_t (ar_chan_t), | |
| .r_chan_t (r_chan_t), | |
| .axi_req_t (axi_req_t), | |
| .axi_resp_t (axi_resp_t) | |
| ) i_axi_fifo ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i, | |
| .slv_req_i (slv_req), | |
| .slv_resp_o(slv_resp), | |
| .mst_req_o (mst_req), | |
| .mst_resp_i(mst_resp) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_fifo_delay_dyn #( | |
| parameter type aw_chan_t = logic, | |
| parameter type w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic, | |
| parameter int unsigned DepthAR = 4, | |
| parameter int unsigned DepthAW = 4, | |
| parameter int unsigned DepthR = 4, | |
| parameter int unsigned DepthW = 4, | |
| parameter int unsigned DepthB = 4, | |
| parameter int unsigned MaxDelay = 1024, | |
| localparam int unsigned DelayWidth = $clog2(MaxDelay) + 1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic [DelayWidth-1:0] aw_delay_i, | |
| input logic [DelayWidth-1:0] w_delay_i, | |
| input logic [DelayWidth-1:0] b_delay_i, | |
| input logic [DelayWidth-1:0] ar_delay_i, | |
| input logic [DelayWidth-1:0] r_delay_i, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| if (DepthAR > 0) begin | |
| stream_fifo_delay_dyn #( | |
| .payload_t ( ar_chan_t ), | |
| .MaxDelay ( MaxDelay ), | |
| .Depth ( DepthAR ) | |
| ) i_ar_fifo_delay ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .delay_i ( ar_delay_i ), | |
| .payload_i ( slv_req_i.ar ), | |
| .ready_o ( slv_resp_o.ar_ready ), | |
| .valid_i ( slv_req_i.ar_valid ), | |
| .payload_o ( mst_req_o.ar ), | |
| .ready_i ( mst_resp_i.ar_ready ), | |
| .valid_o ( mst_req_o.ar_valid ) | |
| ); | |
| end else begin | |
| assign mst_req_o.ar = slv_req_i.ar; | |
| assign mst_req_o.ar_valid = slv_req_i.ar_valid; | |
| assign slv_resp_o.ar_ready = mst_resp_i.ar_ready; | |
| end | |
| if (DepthAW > 0) begin | |
| stream_fifo_delay_dyn #( | |
| .payload_t ( aw_chan_t ), | |
| .MaxDelay ( MaxDelay ), | |
| .Depth ( DepthAW ) | |
| ) i_aw_fifo_delay ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .delay_i ( aw_delay_i ), | |
| .payload_i ( slv_req_i.aw ), | |
| .ready_o ( slv_resp_o.aw_ready ), | |
| .valid_i ( slv_req_i.aw_valid ), | |
| .payload_o ( mst_req_o.aw ), | |
| .ready_i ( mst_resp_i.aw_ready ), | |
| .valid_o ( mst_req_o.aw_valid ) | |
| ); | |
| end else begin | |
| assign mst_req_o.aw = slv_req_i.aw; | |
| assign mst_req_o.aw_valid = slv_req_i.aw_valid; | |
| assign slv_resp_o.aw_ready = mst_resp_i.aw_ready; | |
| end | |
| if (DepthR > 0) begin | |
| stream_fifo_delay_dyn #( | |
| .payload_t ( r_chan_t ), | |
| .MaxDelay ( MaxDelay ), | |
| .Depth ( DepthR ) | |
| ) i_r_fifo_delay ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .delay_i ( r_delay_i ), | |
| .payload_i ( mst_resp_i.r ), | |
| .ready_o ( mst_req_o.r_ready ), | |
| .valid_i ( mst_resp_i.r_valid ), | |
| .payload_o ( slv_resp_o.r ), | |
| .ready_i ( slv_req_i.r_ready ), | |
| .valid_o ( slv_resp_o.r_valid ) | |
| ); | |
| end else begin | |
| assign mst_req_o.r_ready = slv_req_i.r_ready; | |
| assign slv_resp_o.r_valid = mst_resp_i.r_valid; | |
| assign slv_resp_o.r = mst_resp_i.r; | |
| end | |
| if (DepthW > 0) begin | |
| stream_fifo_delay_dyn #( | |
| .payload_t ( w_chan_t ), | |
| .MaxDelay ( MaxDelay ), | |
| .Depth ( DepthW ) | |
| ) i_w_fifo_delay ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .delay_i ( w_delay_i ), | |
| .payload_i ( slv_req_i.w ), | |
| .ready_o ( slv_resp_o.w_ready ), | |
| .valid_i ( slv_req_i.w_valid ), | |
| .payload_o ( mst_req_o.w ), | |
| .ready_i ( mst_resp_i.w_ready ), | |
| .valid_o ( mst_req_o.w_valid ) | |
| ); | |
| end else begin | |
| assign mst_req_o.w = slv_req_i.w; | |
| assign mst_req_o.w_valid = slv_req_i.w_valid; | |
| assign slv_resp_o.w_ready = mst_resp_i.w_ready; | |
| end | |
| if (DepthB > 0) begin | |
| stream_fifo_delay_dyn #( | |
| .payload_t ( b_chan_t ), | |
| .MaxDelay ( MaxDelay ), | |
| .Depth ( DepthB ) | |
| ) i_b_fifo_delay ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .delay_i ( b_delay_i ), | |
| .payload_i ( mst_resp_i.b ), | |
| .ready_o ( mst_req_o.b_ready ), | |
| .valid_i ( mst_resp_i.b_valid ), | |
| .payload_o ( slv_resp_o.b ), | |
| .ready_i ( slv_req_i.b_ready ), | |
| .valid_o ( slv_resp_o.b_valid ) | |
| ); | |
| end else begin | |
| assign mst_req_o.b_ready = slv_req_i.b_ready; | |
| assign slv_resp_o.b = mst_resp_i.b; | |
| assign slv_resp_o.b_valid = mst_resp_i.b_valid; | |
| end | |
| endmodule | |
| module axi_fifo_delay_dyn_intf #( | |
| parameter int unsigned AXI_ID_WIDTH = 0, | |
| parameter int unsigned AXI_ADDR_WIDTH = 0, | |
| parameter int unsigned AXI_DATA_WIDTH = 0, | |
| parameter int unsigned AXI_USER_WIDTH = 0, | |
| parameter int unsigned DEPTH_AR = 4, | |
| parameter int unsigned DEPTH_AW = 4, | |
| parameter int unsigned DEPTH_R = 4, | |
| parameter int unsigned DEPTH_W = 4, | |
| parameter int unsigned DEPTH_B = 4, | |
| parameter int unsigned MAX_DELAY = 0, | |
| parameter int unsigned DELAY_WIDTH = $clog2(MAX_DELAY) + 1 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic [DELAY_WIDTH-1:0] aw_delay_i, | |
| input logic [DELAY_WIDTH-1:0] w_delay_i, | |
| input logic [DELAY_WIDTH-1:0] b_delay_i, | |
| input logic [DELAY_WIDTH-1:0] ar_delay_i, | |
| input logic [DELAY_WIDTH-1:0] r_delay_i, | |
| AXI_BUS.Slave slv, | |
| AXI_BUS.Master mst | |
| ); | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| b_chan_t b; | |
| logic r_valid; | |
| r_chan_t r; | |
| } axi_resp_t; | |
| axi_req_t slv_req, mst_req; | |
| axi_resp_t slv_resp, mst_resp; | |
| assign slv_req.aw.id = slv.aw_id; | |
| assign slv_req.aw.addr = slv.aw_addr; | |
| assign slv_req.aw.len = slv.aw_len; | |
| assign slv_req.aw.size = slv.aw_size; | |
| assign slv_req.aw.burst = slv.aw_burst; | |
| assign slv_req.aw.lock = slv.aw_lock; | |
| assign slv_req.aw.cache = slv.aw_cache; | |
| assign slv_req.aw.prot = slv.aw_prot; | |
| assign slv_req.aw.qos = slv.aw_qos; | |
| assign slv_req.aw.region = slv.aw_region; | |
| assign slv_req.aw.atop = slv.aw_atop; | |
| assign slv_req.aw.user = slv.aw_user; | |
| assign slv_req.aw_valid = slv.aw_valid; | |
| assign slv_req.w.data = slv.w_data; | |
| assign slv_req.w.strb = slv.w_strb; | |
| assign slv_req.w.last = slv.w_last; | |
| assign slv_req.w.user = slv.w_user; | |
| assign slv_req.w_valid = slv.w_valid; | |
| assign slv_req.b_ready = slv.b_ready; | |
| assign slv_req.ar.id = slv.ar_id; | |
| assign slv_req.ar.addr = slv.ar_addr; | |
| assign slv_req.ar.len = slv.ar_len; | |
| assign slv_req.ar.size = slv.ar_size; | |
| assign slv_req.ar.burst = slv.ar_burst; | |
| assign slv_req.ar.lock = slv.ar_lock; | |
| assign slv_req.ar.cache = slv.ar_cache; | |
| assign slv_req.ar.prot = slv.ar_prot; | |
| assign slv_req.ar.qos = slv.ar_qos; | |
| assign slv_req.ar.region = slv.ar_region; | |
| assign slv_req.ar.user = slv.ar_user; | |
| assign slv_req.ar_valid = slv.ar_valid; | |
| assign slv_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = slv_resp.aw_ready; | |
| assign slv.ar_ready = slv_resp.ar_ready; | |
| assign slv.w_ready = slv_resp.w_ready; | |
| assign slv.b_valid = slv_resp.b_valid; | |
| assign slv.b_id = slv_resp.b.id; | |
| assign slv.b_resp = slv_resp.b.resp; | |
| assign slv.b_user = slv_resp.b.user; | |
| assign slv.r_valid = slv_resp.r_valid; | |
| assign slv.r_id = slv_resp.r.id; | |
| assign slv.r_data = slv_resp.r.data; | |
| assign slv.r_resp = slv_resp.r.resp; | |
| assign slv.r_last = slv_resp.r.last; | |
| assign slv.r_user = slv_resp.r.user; | |
| assign mst.aw_id = mst_req.aw.id; | |
| assign mst.aw_addr = mst_req.aw.addr; | |
| assign mst.aw_len = mst_req.aw.len; | |
| assign mst.aw_size = mst_req.aw.size; | |
| assign mst.aw_burst = mst_req.aw.burst; | |
| assign mst.aw_lock = mst_req.aw.lock; | |
| assign mst.aw_cache = mst_req.aw.cache; | |
| assign mst.aw_prot = mst_req.aw.prot; | |
| assign mst.aw_qos = mst_req.aw.qos; | |
| assign mst.aw_region = mst_req.aw.region; | |
| assign mst.aw_atop = mst_req.aw.atop; | |
| assign mst.aw_user = mst_req.aw.user; | |
| assign mst.aw_valid = mst_req.aw_valid; | |
| assign mst.w_data = mst_req.w.data; | |
| assign mst.w_strb = mst_req.w.strb; | |
| assign mst.w_last = mst_req.w.last; | |
| assign mst.w_user = mst_req.w.user; | |
| assign mst.w_valid = mst_req.w_valid; | |
| assign mst.b_ready = mst_req.b_ready; | |
| assign mst.ar_id = mst_req.ar.id; | |
| assign mst.ar_addr = mst_req.ar.addr; | |
| assign mst.ar_len = mst_req.ar.len; | |
| assign mst.ar_size = mst_req.ar.size; | |
| assign mst.ar_burst = mst_req.ar.burst; | |
| assign mst.ar_lock = mst_req.ar.lock; | |
| assign mst.ar_cache = mst_req.ar.cache; | |
| assign mst.ar_prot = mst_req.ar.prot; | |
| assign mst.ar_qos = mst_req.ar.qos; | |
| assign mst.ar_region = mst_req.ar.region; | |
| assign mst.ar_user = mst_req.ar.user; | |
| assign mst.ar_valid = mst_req.ar_valid; | |
| assign mst.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = mst.aw_ready; | |
| assign mst_resp.ar_ready = mst.ar_ready; | |
| assign mst_resp.w_ready = mst.w_ready; | |
| assign mst_resp.b_valid = mst.b_valid; | |
| assign mst_resp.b.id = mst.b_id; | |
| assign mst_resp.b.resp = mst.b_resp; | |
| assign mst_resp.b.user = mst.b_user; | |
| assign mst_resp.r_valid = mst.r_valid; | |
| assign mst_resp.r.id = mst.r_id; | |
| assign mst_resp.r.data = mst.r_data; | |
| assign mst_resp.r.resp = mst.r_resp; | |
| assign mst_resp.r.last = mst.r_last; | |
| assign mst_resp.r.user = mst.r_user; | |
| axi_fifo_delay_dyn #( | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .DepthAR ( DEPTH_AR ), | |
| .DepthAW ( DEPTH_AW ), | |
| .DepthR ( DEPTH_R ), | |
| .DepthW ( DEPTH_W ), | |
| .DepthB ( DEPTH_B ), | |
| .MaxDelay ( MAX_DELAY ) | |
| ) i_axi_fifo_delay_dyn ( | |
| .clk_i, | |
| .rst_ni, | |
| .aw_delay_i ( aw_delay_i ), | |
| .w_delay_i ( w_delay_i ), | |
| .b_delay_i ( b_delay_i ), | |
| .ar_delay_i ( ar_delay_i ), | |
| .r_delay_i ( r_delay_i ), | |
| .slv_req_i ( slv_req ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_req_o ( mst_req ), | |
| .mst_resp_i ( mst_resp ) | |
| ); | |
| endmodule | |
| module stream_fifo_delay_dyn #( | |
| parameter type payload_t = logic, | |
| parameter int unsigned MaxDelay = 1024, | |
| parameter int unsigned Depth = 4, | |
| parameter int unsigned CounterWidth = $clog2(MaxDelay) + 1 | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic [CounterWidth-1:0] delay_i, | |
| input payload_t payload_i, | |
| output logic ready_o, | |
| input logic valid_i, | |
| output payload_t payload_o, | |
| input logic ready_i, | |
| output logic valid_o | |
| ); | |
| if (Depth & (Depth - 1) == 0) | |
| $fatal(1, "Depth must be a power of two"); | |
| localparam int unsigned BookeepingBits = $clog2(Depth) + 1; | |
| logic [BookeepingBits-1:0] ready_count_d, ready_count_q; | |
| logic [CounterWidth-1:0] count_val; | |
| logic [CounterWidth-1:0] head_deadline; | |
| logic [CounterWidth-1:0] tail_deadline; | |
| payload_t head_data; | |
| logic fifo_dead_full, fifo_dead_empty, fifo_dead_push, fifo_dead_pop; | |
| logic fifo_data_full, fifo_data_empty, fifo_data_push, fifo_data_pop; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| ready_count_q <= ('0); | |
| end else begin | |
| ready_count_q <= (ready_count_d); | |
| end | |
| end | |
| always_comb begin | |
| ready_count_d = ready_count_q; | |
| if (fifo_dead_pop) | |
| ready_count_d += 1; | |
| if (fifo_data_pop) | |
| ready_count_d -= 1; | |
| end | |
| assign tail_deadline = count_val + delay_i + 1; | |
| assign fifo_data_push = ~fifo_data_full & valid_i; | |
| assign fifo_dead_push = fifo_data_push; | |
| assign fifo_dead_pop = (count_val == head_deadline) & ~fifo_dead_empty; | |
| assign fifo_data_pop = valid_o & ready_i; | |
| assign valid_o = (ready_count_q > 0); | |
| assign ready_o = ~fifo_data_full; | |
| assign payload_o = head_data; | |
| counter #( | |
| .WIDTH ( CounterWidth ) | |
| ) i_counter ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .clear_i ( 1'b0 ), | |
| .en_i ( 1'b1 ), | |
| .load_i ( 1'b0 ), | |
| .down_i ( 1'b0 ), | |
| .d_i ( '0 ), | |
| .q_o ( count_val ), | |
| .overflow_o ( ) | |
| ); | |
| fifo_v3 #( | |
| .DATA_WIDTH ( $bits(payload_t) ), | |
| .DEPTH ( Depth ), | |
| .FALL_THROUGH ( 1'b0 ) | |
| ) data_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .data_i ( payload_i ), | |
| .push_i ( fifo_data_push ), | |
| .full_o ( fifo_data_full ), | |
| .data_o ( head_data ), | |
| .pop_i ( fifo_data_pop ), | |
| .empty_o ( fifo_data_empty ), | |
| .usage_o ( ) | |
| ); | |
| fifo_v3 #( | |
| .DATA_WIDTH ( CounterWidth ), | |
| .DEPTH ( Depth ), | |
| .FALL_THROUGH ( 1'b0 ) | |
| ) deadline_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .data_i ( tail_deadline ), | |
| .push_i ( fifo_dead_push ), | |
| .full_o ( fifo_dead_full ), | |
| .data_o ( head_deadline ), | |
| .pop_i ( fifo_dead_pop ), | |
| .empty_o ( fifo_dead_empty ), | |
| .usage_o ( ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_id_remap #( | |
| parameter int unsigned AxiSlvPortIdWidth = 32'd0, | |
| parameter int unsigned AxiSlvPortMaxUniqIds = 32'd0, | |
| parameter int unsigned AxiMaxTxnsPerId = 32'd0, | |
| parameter int unsigned AxiMstPortIdWidth = 32'd0, | |
| parameter type slv_req_t = logic, | |
| parameter type slv_resp_t = logic, | |
| parameter type mst_req_t = logic, | |
| parameter type mst_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input slv_req_t slv_req_i, | |
| output slv_resp_t slv_resp_o, | |
| output mst_req_t mst_req_o, | |
| input mst_resp_t mst_resp_i | |
| ); | |
| assign mst_req_o.aw.addr = slv_req_i.aw.addr; | |
| assign mst_req_o.aw.len = slv_req_i.aw.len; | |
| assign mst_req_o.aw.size = slv_req_i.aw.size; | |
| assign mst_req_o.aw.burst = slv_req_i.aw.burst; | |
| assign mst_req_o.aw.lock = slv_req_i.aw.lock; | |
| assign mst_req_o.aw.cache = slv_req_i.aw.cache; | |
| assign mst_req_o.aw.prot = slv_req_i.aw.prot; | |
| assign mst_req_o.aw.qos = slv_req_i.aw.qos; | |
| assign mst_req_o.aw.region = slv_req_i.aw.region; | |
| assign mst_req_o.aw.atop = slv_req_i.aw.atop; | |
| assign mst_req_o.aw.user = slv_req_i.aw.user; | |
| assign mst_req_o.w = slv_req_i.w; | |
| assign mst_req_o.w_valid = slv_req_i.w_valid; | |
| assign slv_resp_o.w_ready = mst_resp_i.w_ready; | |
| assign slv_resp_o.b.resp = mst_resp_i.b.resp; | |
| assign slv_resp_o.b.user = mst_resp_i.b.user; | |
| assign slv_resp_o.b_valid = mst_resp_i.b_valid; | |
| assign mst_req_o.b_ready = slv_req_i.b_ready; | |
| assign mst_req_o.ar.addr = slv_req_i.ar.addr; | |
| assign mst_req_o.ar.len = slv_req_i.ar.len; | |
| assign mst_req_o.ar.size = slv_req_i.ar.size; | |
| assign mst_req_o.ar.burst = slv_req_i.ar.burst; | |
| assign mst_req_o.ar.lock = slv_req_i.ar.lock; | |
| assign mst_req_o.ar.cache = slv_req_i.ar.cache; | |
| assign mst_req_o.ar.prot = slv_req_i.ar.prot; | |
| assign mst_req_o.ar.qos = slv_req_i.ar.qos; | |
| assign mst_req_o.ar.region = slv_req_i.ar.region; | |
| assign mst_req_o.ar.user = slv_req_i.ar.user; | |
| assign slv_resp_o.r.data = mst_resp_i.r.data; | |
| assign slv_resp_o.r.resp = mst_resp_i.r.resp; | |
| assign slv_resp_o.r.last = mst_resp_i.r.last; | |
| assign slv_resp_o.r.user = mst_resp_i.r.user; | |
| assign slv_resp_o.r_valid = mst_resp_i.r_valid; | |
| assign mst_req_o.r_ready = slv_req_i.r_ready; | |
| localparam int unsigned IdxWidth = cf_math_pkg::idx_width(AxiSlvPortMaxUniqIds); | |
| typedef logic [AxiSlvPortMaxUniqIds-1:0] field_t; | |
| typedef logic [AxiSlvPortIdWidth-1:0] id_inp_t; | |
| typedef logic [IdxWidth-1:0] idx_t; | |
| field_t wr_free, rd_free, both_free; | |
| id_inp_t rd_push_inp_id; | |
| idx_t wr_free_oup_id, rd_free_oup_id, both_free_oup_id, | |
| wr_push_oup_id, rd_push_oup_id, | |
| wr_exists_id, rd_exists_id; | |
| logic wr_exists, rd_exists, | |
| wr_exists_full, rd_exists_full, | |
| wr_full, rd_full, | |
| wr_push, rd_push; | |
| axi_id_remap_table #( | |
| .InpIdWidth ( AxiSlvPortIdWidth ), | |
| .MaxUniqInpIds ( AxiSlvPortMaxUniqIds ), | |
| .MaxTxnsPerId ( AxiMaxTxnsPerId ) | |
| ) i_wr_table ( | |
| .clk_i, | |
| .rst_ni, | |
| .free_o ( wr_free ), | |
| .free_oup_id_o ( wr_free_oup_id ), | |
| .full_o ( wr_full ), | |
| .push_i ( wr_push ), | |
| .push_inp_id_i ( slv_req_i.aw.id ), | |
| .push_oup_id_i ( wr_push_oup_id ), | |
| .exists_inp_id_i ( slv_req_i.aw.id ), | |
| .exists_o ( wr_exists ), | |
| .exists_oup_id_o ( wr_exists_id ), | |
| .exists_full_o ( wr_exists_full ), | |
| .pop_i ( slv_resp_o.b_valid && slv_req_i.b_ready ), | |
| .pop_oup_id_i ( mst_resp_i.b.id[IdxWidth-1:0] ), | |
| .pop_inp_id_o ( slv_resp_o.b.id ) | |
| ); | |
| axi_id_remap_table #( | |
| .InpIdWidth ( AxiSlvPortIdWidth ), | |
| .MaxUniqInpIds ( AxiSlvPortMaxUniqIds ), | |
| .MaxTxnsPerId ( AxiMaxTxnsPerId ) | |
| ) i_rd_table ( | |
| .clk_i, | |
| .rst_ni, | |
| .free_o ( rd_free ), | |
| .free_oup_id_o ( rd_free_oup_id ), | |
| .full_o ( rd_full ), | |
| .push_i ( rd_push ), | |
| .push_inp_id_i ( rd_push_inp_id ), | |
| .push_oup_id_i ( rd_push_oup_id ), | |
| .exists_inp_id_i ( slv_req_i.ar.id ), | |
| .exists_o ( rd_exists ), | |
| .exists_oup_id_o ( rd_exists_id ), | |
| .exists_full_o ( rd_exists_full ), | |
| .pop_i ( slv_resp_o.r_valid && slv_req_i.r_ready && slv_resp_o.r.last ), | |
| .pop_oup_id_i ( mst_resp_i.r.id[IdxWidth-1:0] ), | |
| .pop_inp_id_o ( slv_resp_o.r.id ) | |
| ); | |
| assign both_free = wr_free & rd_free; | |
| lzc #( | |
| .WIDTH ( AxiSlvPortMaxUniqIds ), | |
| .MODE ( 1'b0 ) | |
| ) i_lzc ( | |
| .in_i ( both_free ), | |
| .cnt_o ( both_free_oup_id ), | |
| .empty_o ( ) | |
| ); | |
| localparam ZeroWidth = AxiMstPortIdWidth - IdxWidth; | |
| assign mst_req_o.ar.id = {{ZeroWidth{1'b0}}, rd_push_oup_id}; | |
| assign mst_req_o.aw.id = {{ZeroWidth{1'b0}}, wr_push_oup_id}; | |
| enum logic [1:0] {Ready, HoldAR, HoldAW, HoldAx} state_d, state_q; | |
| idx_t ar_id_d, ar_id_q, | |
| aw_id_d, aw_id_q; | |
| logic ar_prio_d, ar_prio_q; | |
| always_comb begin | |
| mst_req_o.aw_valid = 1'b0; | |
| slv_resp_o.aw_ready = 1'b0; | |
| wr_push = 1'b0; | |
| wr_push_oup_id = '0; | |
| mst_req_o.ar_valid = 1'b0; | |
| slv_resp_o.ar_ready = 1'b0; | |
| rd_push = 1'b0; | |
| rd_push_inp_id = '0; | |
| rd_push_oup_id = '0; | |
| ar_id_d = ar_id_q; | |
| aw_id_d = aw_id_q; | |
| ar_prio_d = ar_prio_q; | |
| state_d = state_q; | |
| unique case (state_q) | |
| Ready: begin | |
| if (slv_req_i.ar_valid) begin | |
| if ((rd_exists && !rd_exists_full) || (!rd_exists && !rd_full)) begin | |
| rd_push_inp_id = slv_req_i.ar.id; | |
| rd_push_oup_id = rd_exists ? rd_exists_id : rd_free_oup_id; | |
| mst_req_o.ar_valid = 1'b1; | |
| rd_push = 1'b1; | |
| end | |
| end | |
| if (slv_req_i.aw_valid) begin | |
| if (!slv_req_i.aw.atop[axi_pkg::ATOP_R_RESP]) begin | |
| if ((wr_exists && !wr_exists_full) || (!wr_exists && !wr_full)) begin | |
| wr_push_oup_id = wr_exists ? wr_exists_id : wr_free_oup_id; | |
| mst_req_o.aw_valid = 1'b1; | |
| wr_push = 1'b1; | |
| end | |
| end else if (!(ar_prio_q && mst_req_o.ar_valid)) begin | |
| mst_req_o.ar_valid = 1'b0; | |
| slv_resp_o.ar_ready = 1'b0; | |
| rd_push = 1'b0; | |
| if ((|both_free)) begin | |
| wr_push_oup_id = both_free_oup_id; | |
| rd_push_inp_id = slv_req_i.aw.id; | |
| rd_push_oup_id = both_free_oup_id; | |
| mst_req_o.aw_valid = 1'b1; | |
| rd_push = 1'b1; | |
| wr_push = 1'b1; | |
| ar_prio_d = 1'b1; | |
| end | |
| end | |
| end | |
| if (mst_req_o.ar_valid) begin | |
| slv_resp_o.ar_ready = mst_resp_i.ar_ready; | |
| if (!mst_resp_i.ar_ready) begin | |
| ar_id_d = rd_push_oup_id; | |
| end | |
| end | |
| if (mst_req_o.aw_valid) begin | |
| slv_resp_o.aw_ready = mst_resp_i.aw_ready; | |
| if (!mst_resp_i.aw_ready) begin | |
| aw_id_d = wr_push_oup_id; | |
| end | |
| end | |
| if ({mst_req_o.ar_valid, mst_resp_i.ar_ready, | |
| mst_req_o.aw_valid, mst_resp_i.aw_ready} == 4'b1010) begin | |
| state_d = HoldAx; | |
| end else if ({mst_req_o.ar_valid, mst_resp_i.ar_ready} == 2'b10) begin | |
| state_d = HoldAR; | |
| end else if ({mst_req_o.aw_valid, mst_resp_i.aw_ready} == 2'b10) begin | |
| state_d = HoldAW; | |
| end else begin | |
| state_d = Ready; | |
| end | |
| if (mst_req_o.ar_valid && mst_resp_i.ar_ready) begin | |
| ar_prio_d = 1'b0; | |
| end | |
| end | |
| HoldAR: begin | |
| rd_push_oup_id = ar_id_q; | |
| mst_req_o.ar_valid = 1'b1; | |
| slv_resp_o.ar_ready = mst_resp_i.ar_ready; | |
| if (mst_resp_i.ar_ready) begin | |
| state_d = Ready; | |
| ar_prio_d = 1'b0; | |
| end | |
| end | |
| HoldAW: begin | |
| wr_push_oup_id = aw_id_q; | |
| mst_req_o.aw_valid = 1'b1; | |
| slv_resp_o.aw_ready = mst_resp_i.aw_ready; | |
| if (mst_resp_i.aw_ready) begin | |
| state_d = Ready; | |
| end | |
| end | |
| HoldAx: begin | |
| rd_push_oup_id = ar_id_q; | |
| mst_req_o.ar_valid = 1'b1; | |
| slv_resp_o.ar_ready = mst_resp_i.ar_ready; | |
| wr_push_oup_id = aw_id_q; | |
| mst_req_o.aw_valid = 1'b1; | |
| slv_resp_o.aw_ready = mst_resp_i.aw_ready; | |
| unique case ({mst_resp_i.ar_ready, mst_resp_i.aw_ready}) | |
| 2'b01: state_d = HoldAR; | |
| 2'b10: state_d = HoldAW; | |
| 2'b11: state_d = Ready; | |
| default: ; | |
| endcase | |
| if (mst_resp_i.ar_ready) begin | |
| ar_prio_d = 1'b0; | |
| end | |
| end | |
| default: state_d = Ready; | |
| endcase | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| ar_id_q <= ('0); | |
| end else begin | |
| ar_id_q <= (ar_id_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| ar_prio_q <= (1'b0); | |
| end else begin | |
| ar_prio_q <= (ar_prio_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| aw_id_q <= ('0); | |
| end else begin | |
| aw_id_q <= (aw_id_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| state_q <= (Ready); | |
| end else begin | |
| state_q <= (state_d); | |
| end | |
| end | |
| endmodule | |
| module axi_id_remap_table #( | |
| parameter int unsigned InpIdWidth = 32'd0, | |
| parameter int unsigned MaxUniqInpIds = 32'd0, | |
| parameter int unsigned MaxTxnsPerId = 32'd0, | |
| localparam type id_inp_t = logic [InpIdWidth-1:0], | |
| localparam int unsigned IdxWidth = cf_math_pkg::idx_width(MaxUniqInpIds), | |
| localparam type idx_t = logic [IdxWidth-1:0], | |
| localparam type field_t = logic [MaxUniqInpIds-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| output field_t free_o, | |
| output idx_t free_oup_id_o, | |
| output logic full_o, | |
| input logic push_i, | |
| input id_inp_t push_inp_id_i, | |
| input idx_t push_oup_id_i, | |
| input id_inp_t exists_inp_id_i, | |
| output logic exists_o, | |
| output idx_t exists_oup_id_o, | |
| output logic exists_full_o, | |
| input logic pop_i, | |
| input idx_t pop_oup_id_i, | |
| output id_inp_t pop_inp_id_o | |
| ); | |
| localparam int unsigned CntWidth = $clog2(MaxTxnsPerId+1); | |
| typedef logic [CntWidth-1:0] cnt_t; | |
| typedef struct packed { | |
| id_inp_t inp_id; | |
| cnt_t cnt; | |
| } entry_t; | |
| entry_t [MaxUniqInpIds-1:0] table_d, table_q; | |
| for (genvar i = 0; i < MaxUniqInpIds; i++) begin : gen_free_o | |
| assign free_o[i] = table_q[i].cnt == '0; | |
| end | |
| lzc #( | |
| .WIDTH ( MaxUniqInpIds ), | |
| .MODE ( 1'b0 ) | |
| ) i_lzc_free ( | |
| .in_i ( free_o ), | |
| .cnt_o ( free_oup_id_o ), | |
| .empty_o ( full_o ) | |
| ); | |
| if (MaxUniqInpIds == 1) begin : gen_pop_for_single_unique_inp_id | |
| assign pop_inp_id_o = table_q[0].inp_id; | |
| end else begin : gen_pop_for_multiple_unique_inp_ids | |
| assign pop_inp_id_o = table_q[pop_oup_id_i].inp_id; | |
| end | |
| field_t match; | |
| for (genvar i = 0; i < MaxUniqInpIds; i++) begin : gen_match | |
| assign match[i] = table_q[i].cnt > 0 && table_q[i].inp_id == exists_inp_id_i; | |
| end | |
| logic no_match; | |
| lzc #( | |
| .WIDTH ( MaxUniqInpIds ), | |
| .MODE ( 1'b0 ) | |
| ) i_lzc_match ( | |
| .in_i ( match ), | |
| .cnt_o ( exists_oup_id_o ), | |
| .empty_o ( no_match ) | |
| ); | |
| assign exists_o = ~no_match; | |
| if (MaxUniqInpIds == 1) begin : gen_exists_full_for_single_unique_inp_id | |
| assign exists_full_o = table_q[0].cnt == MaxTxnsPerId; | |
| end else begin : gen_exists_full_for_multiple_unique_inp_ids | |
| assign exists_full_o = table_q[exists_oup_id_o].cnt == MaxTxnsPerId; | |
| end | |
| always_comb begin | |
| table_d = table_q; | |
| if (push_i) begin | |
| table_d[push_oup_id_i].inp_id = push_inp_id_i; | |
| table_d[push_oup_id_i].cnt += 1; | |
| end | |
| if (pop_i) begin | |
| table_d[pop_oup_id_i].cnt -= 1; | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| table_q <= ('0); | |
| end else begin | |
| table_q <= (table_d); | |
| end | |
| end | |
| endmodule | |
| module axi_id_remap_intf #( | |
| parameter int unsigned AXI_SLV_PORT_ID_WIDTH = 32'd0, | |
| parameter int unsigned AXI_SLV_PORT_MAX_UNIQ_IDS = 32'd0, | |
| parameter int unsigned AXI_MAX_TXNS_PER_ID = 32'd0, | |
| parameter int unsigned AXI_MST_PORT_ID_WIDTH = 32'd0, | |
| parameter int unsigned AXI_ADDR_WIDTH = 32'd0, | |
| parameter int unsigned AXI_DATA_WIDTH = 32'd0, | |
| parameter int unsigned AXI_USER_WIDTH = 32'd0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| AXI_BUS.Slave slv, | |
| AXI_BUS.Master mst | |
| ); | |
| typedef logic [AXI_SLV_PORT_ID_WIDTH-1:0] slv_id_t; | |
| typedef logic [AXI_MST_PORT_ID_WIDTH-1:0] mst_id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] axi_addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] axi_data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] axi_strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] axi_user_t; | |
| typedef struct packed { | |
| slv_id_t id; | |
| axi_addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| axi_user_t user; | |
| } slv_aw_chan_t; | |
| typedef struct packed { | |
| axi_data_t data; | |
| axi_strb_t strb; | |
| logic last; | |
| axi_user_t user; | |
| } slv_w_chan_t; | |
| typedef struct packed { | |
| slv_id_t id; | |
| axi_pkg::resp_t resp; | |
| axi_user_t user; | |
| } slv_b_chan_t; | |
| typedef struct packed { | |
| slv_id_t id; | |
| axi_addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_user_t user; | |
| } slv_ar_chan_t; | |
| typedef struct packed { | |
| slv_id_t id; | |
| axi_data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| axi_user_t user; | |
| } slv_r_chan_t; | |
| typedef struct packed { | |
| slv_aw_chan_t aw; | |
| logic aw_valid; | |
| slv_w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| slv_ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } slv_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| slv_b_chan_t b; | |
| logic r_valid; | |
| slv_r_chan_t r; | |
| } slv_resp_t; | |
| typedef struct packed { | |
| mst_id_t id; | |
| axi_addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| axi_user_t user; | |
| } mst_aw_chan_t; | |
| typedef struct packed { | |
| axi_data_t data; | |
| axi_strb_t strb; | |
| logic last; | |
| axi_user_t user; | |
| } mst_w_chan_t; | |
| typedef struct packed { | |
| mst_id_t id; | |
| axi_pkg::resp_t resp; | |
| axi_user_t user; | |
| } mst_b_chan_t; | |
| typedef struct packed { | |
| mst_id_t id; | |
| axi_addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_user_t user; | |
| } mst_ar_chan_t; | |
| typedef struct packed { | |
| mst_id_t id; | |
| axi_data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| axi_user_t user; | |
| } mst_r_chan_t; | |
| typedef struct packed { | |
| mst_aw_chan_t aw; | |
| logic aw_valid; | |
| mst_w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| mst_ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } mst_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| mst_b_chan_t b; | |
| logic r_valid; | |
| mst_r_chan_t r; | |
| } mst_resp_t; | |
| slv_req_t slv_req; | |
| slv_resp_t slv_resp; | |
| mst_req_t mst_req; | |
| mst_resp_t mst_resp; | |
| assign slv_req.aw.id = slv.aw_id; | |
| assign slv_req.aw.addr = slv.aw_addr; | |
| assign slv_req.aw.len = slv.aw_len; | |
| assign slv_req.aw.size = slv.aw_size; | |
| assign slv_req.aw.burst = slv.aw_burst; | |
| assign slv_req.aw.lock = slv.aw_lock; | |
| assign slv_req.aw.cache = slv.aw_cache; | |
| assign slv_req.aw.prot = slv.aw_prot; | |
| assign slv_req.aw.qos = slv.aw_qos; | |
| assign slv_req.aw.region = slv.aw_region; | |
| assign slv_req.aw.atop = slv.aw_atop; | |
| assign slv_req.aw.user = slv.aw_user; | |
| assign slv_req.aw_valid = slv.aw_valid; | |
| assign slv_req.w.data = slv.w_data; | |
| assign slv_req.w.strb = slv.w_strb; | |
| assign slv_req.w.last = slv.w_last; | |
| assign slv_req.w.user = slv.w_user; | |
| assign slv_req.w_valid = slv.w_valid; | |
| assign slv_req.b_ready = slv.b_ready; | |
| assign slv_req.ar.id = slv.ar_id; | |
| assign slv_req.ar.addr = slv.ar_addr; | |
| assign slv_req.ar.len = slv.ar_len; | |
| assign slv_req.ar.size = slv.ar_size; | |
| assign slv_req.ar.burst = slv.ar_burst; | |
| assign slv_req.ar.lock = slv.ar_lock; | |
| assign slv_req.ar.cache = slv.ar_cache; | |
| assign slv_req.ar.prot = slv.ar_prot; | |
| assign slv_req.ar.qos = slv.ar_qos; | |
| assign slv_req.ar.region = slv.ar_region; | |
| assign slv_req.ar.user = slv.ar_user; | |
| assign slv_req.ar_valid = slv.ar_valid; | |
| assign slv_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = slv_resp.aw_ready; | |
| assign slv.ar_ready = slv_resp.ar_ready; | |
| assign slv.w_ready = slv_resp.w_ready; | |
| assign slv.b_valid = slv_resp.b_valid; | |
| assign slv.b_id = slv_resp.b.id; | |
| assign slv.b_resp = slv_resp.b.resp; | |
| assign slv.b_user = slv_resp.b.user; | |
| assign slv.r_valid = slv_resp.r_valid; | |
| assign slv.r_id = slv_resp.r.id; | |
| assign slv.r_data = slv_resp.r.data; | |
| assign slv.r_resp = slv_resp.r.resp; | |
| assign slv.r_last = slv_resp.r.last; | |
| assign slv.r_user = slv_resp.r.user; | |
| assign mst.aw_id = mst_req.aw.id; | |
| assign mst.aw_addr = mst_req.aw.addr; | |
| assign mst.aw_len = mst_req.aw.len; | |
| assign mst.aw_size = mst_req.aw.size; | |
| assign mst.aw_burst = mst_req.aw.burst; | |
| assign mst.aw_lock = mst_req.aw.lock; | |
| assign mst.aw_cache = mst_req.aw.cache; | |
| assign mst.aw_prot = mst_req.aw.prot; | |
| assign mst.aw_qos = mst_req.aw.qos; | |
| assign mst.aw_region = mst_req.aw.region; | |
| assign mst.aw_atop = mst_req.aw.atop; | |
| assign mst.aw_user = mst_req.aw.user; | |
| assign mst.aw_valid = mst_req.aw_valid; | |
| assign mst.w_data = mst_req.w.data; | |
| assign mst.w_strb = mst_req.w.strb; | |
| assign mst.w_last = mst_req.w.last; | |
| assign mst.w_user = mst_req.w.user; | |
| assign mst.w_valid = mst_req.w_valid; | |
| assign mst.b_ready = mst_req.b_ready; | |
| assign mst.ar_id = mst_req.ar.id; | |
| assign mst.ar_addr = mst_req.ar.addr; | |
| assign mst.ar_len = mst_req.ar.len; | |
| assign mst.ar_size = mst_req.ar.size; | |
| assign mst.ar_burst = mst_req.ar.burst; | |
| assign mst.ar_lock = mst_req.ar.lock; | |
| assign mst.ar_cache = mst_req.ar.cache; | |
| assign mst.ar_prot = mst_req.ar.prot; | |
| assign mst.ar_qos = mst_req.ar.qos; | |
| assign mst.ar_region = mst_req.ar.region; | |
| assign mst.ar_user = mst_req.ar.user; | |
| assign mst.ar_valid = mst_req.ar_valid; | |
| assign mst.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = mst.aw_ready; | |
| assign mst_resp.ar_ready = mst.ar_ready; | |
| assign mst_resp.w_ready = mst.w_ready; | |
| assign mst_resp.b_valid = mst.b_valid; | |
| assign mst_resp.b.id = mst.b_id; | |
| assign mst_resp.b.resp = mst.b_resp; | |
| assign mst_resp.b.user = mst.b_user; | |
| assign mst_resp.r_valid = mst.r_valid; | |
| assign mst_resp.r.id = mst.r_id; | |
| assign mst_resp.r.data = mst.r_data; | |
| assign mst_resp.r.resp = mst.r_resp; | |
| assign mst_resp.r.last = mst.r_last; | |
| assign mst_resp.r.user = mst.r_user; | |
| axi_id_remap #( | |
| .AxiSlvPortIdWidth ( AXI_SLV_PORT_ID_WIDTH ), | |
| .AxiSlvPortMaxUniqIds ( AXI_SLV_PORT_MAX_UNIQ_IDS ), | |
| .AxiMaxTxnsPerId ( AXI_MAX_TXNS_PER_ID ), | |
| .AxiMstPortIdWidth ( AXI_MST_PORT_ID_WIDTH ), | |
| .slv_req_t ( slv_req_t ), | |
| .slv_resp_t ( slv_resp_t ), | |
| .mst_req_t ( mst_req_t ), | |
| .mst_resp_t ( mst_resp_t ) | |
| ) i_axi_id_remap ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_req ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_req_o ( mst_req ), | |
| .mst_resp_i ( mst_resp ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_id_prepend #( | |
| parameter int unsigned NoBus = 1, | |
| parameter int unsigned AxiIdWidthSlvPort = 4, | |
| parameter int unsigned AxiIdWidthMstPort = 6, | |
| parameter type slv_aw_chan_t = logic, | |
| parameter type slv_w_chan_t = logic, | |
| parameter type slv_b_chan_t = logic, | |
| parameter type slv_ar_chan_t = logic, | |
| parameter type slv_r_chan_t = logic, | |
| parameter type mst_aw_chan_t = logic, | |
| parameter type mst_w_chan_t = logic, | |
| parameter type mst_b_chan_t = logic, | |
| parameter type mst_ar_chan_t = logic, | |
| parameter type mst_r_chan_t = logic, | |
| parameter int unsigned PreIdWidth = AxiIdWidthMstPort - AxiIdWidthSlvPort | |
| ) ( | |
| input logic [PreIdWidth-1:0] pre_id_i, | |
| input slv_aw_chan_t [NoBus-1:0] slv_aw_chans_i, | |
| input logic [NoBus-1:0] slv_aw_valids_i, | |
| output logic [NoBus-1:0] slv_aw_readies_o, | |
| input slv_w_chan_t [NoBus-1:0] slv_w_chans_i, | |
| input logic [NoBus-1:0] slv_w_valids_i, | |
| output logic [NoBus-1:0] slv_w_readies_o, | |
| output slv_b_chan_t [NoBus-1:0] slv_b_chans_o, | |
| output logic [NoBus-1:0] slv_b_valids_o, | |
| input logic [NoBus-1:0] slv_b_readies_i, | |
| input slv_ar_chan_t [NoBus-1:0] slv_ar_chans_i, | |
| input logic [NoBus-1:0] slv_ar_valids_i, | |
| output logic [NoBus-1:0] slv_ar_readies_o, | |
| output slv_r_chan_t [NoBus-1:0] slv_r_chans_o, | |
| output logic [NoBus-1:0] slv_r_valids_o, | |
| input logic [NoBus-1:0] slv_r_readies_i, | |
| output mst_aw_chan_t [NoBus-1:0] mst_aw_chans_o, | |
| output logic [NoBus-1:0] mst_aw_valids_o, | |
| input logic [NoBus-1:0] mst_aw_readies_i, | |
| output mst_w_chan_t [NoBus-1:0] mst_w_chans_o, | |
| output logic [NoBus-1:0] mst_w_valids_o, | |
| input logic [NoBus-1:0] mst_w_readies_i, | |
| input mst_b_chan_t [NoBus-1:0] mst_b_chans_i, | |
| input logic [NoBus-1:0] mst_b_valids_i, | |
| output logic [NoBus-1:0] mst_b_readies_o, | |
| output mst_ar_chan_t [NoBus-1:0] mst_ar_chans_o, | |
| output logic [NoBus-1:0] mst_ar_valids_o, | |
| input logic [NoBus-1:0] mst_ar_readies_i, | |
| input mst_r_chan_t [NoBus-1:0] mst_r_chans_i, | |
| input logic [NoBus-1:0] mst_r_valids_i, | |
| output logic [NoBus-1:0] mst_r_readies_o | |
| ); | |
| for (genvar i = 0; i < NoBus; i++) begin : gen_id_prepend | |
| if (PreIdWidth == 0) begin : gen_no_prepend | |
| assign mst_aw_chans_o[i] = slv_aw_chans_i[i]; | |
| assign mst_ar_chans_o[i] = slv_ar_chans_i[i]; | |
| end else begin : gen_prepend | |
| always_comb begin | |
| mst_aw_chans_o[i] = mst_aw_chan_t'(slv_aw_chans_i[i]); | |
| mst_ar_chans_o[i] = mst_ar_chan_t'(slv_ar_chans_i[i]); | |
| mst_aw_chans_o[i].id = {pre_id_i, slv_aw_chans_i[i].id[AxiIdWidthSlvPort-1:0]}; | |
| mst_ar_chans_o[i].id = {pre_id_i, slv_ar_chans_i[i].id[AxiIdWidthSlvPort-1:0]}; | |
| end | |
| end | |
| assign slv_b_chans_o[i] = slv_b_chan_t'(mst_b_chans_i[i]); | |
| assign slv_r_chans_o[i] = slv_r_chan_t'(mst_r_chans_i[i]); | |
| end | |
| assign mst_w_chans_o = slv_w_chans_i; | |
| assign mst_aw_valids_o = slv_aw_valids_i; | |
| assign slv_aw_readies_o = mst_aw_readies_i; | |
| assign mst_w_valids_o = slv_w_valids_i; | |
| assign slv_w_readies_o = mst_w_readies_i; | |
| assign slv_b_valids_o = mst_b_valids_i; | |
| assign mst_b_readies_o = slv_b_readies_i; | |
| assign mst_ar_valids_o = slv_ar_valids_i; | |
| assign slv_ar_readies_o = mst_ar_readies_i; | |
| assign slv_r_valids_o = mst_r_valids_i; | |
| assign mst_r_readies_o = slv_r_readies_i; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_inval_filter #( | |
| parameter int unsigned MaxTxns = 32'd0, | |
| parameter int unsigned AddrWidth = 32'd0, | |
| parameter int unsigned L1LineWidth = 32'd0, | |
| parameter type aw_chan_t = logic, | |
| parameter type req_t = logic, | |
| parameter type resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| input req_t slv_req_i, | |
| output resp_t slv_resp_o, | |
| output req_t mst_req_o, | |
| input resp_t mst_resp_i, | |
| output logic [AddrWidth-1:0] inval_addr_o, | |
| output logic inval_valid_o, | |
| input logic inval_ready_i | |
| ); | |
| import cf_math_pkg::idx_width; | |
| logic aw_fifo_full, aw_fifo_empty; | |
| logic aw_fifo_push, aw_fifo_pop; | |
| aw_chan_t aw_fifo_data; | |
| assign aw_fifo_push = en_i & slv_req_i.aw_valid & slv_resp_o.aw_ready; | |
| logic [AddrWidth-1:0] inval_offset_d, inval_offset_q; | |
| assign inval_addr_o = aw_fifo_data.addr + inval_offset_q; | |
| assign inval_valid_o = ~aw_fifo_empty; | |
| always_comb begin : axi | |
| mst_req_o = slv_req_i; | |
| slv_resp_o = mst_resp_i; | |
| if (aw_fifo_full) begin | |
| slv_resp_o.aw_ready = 1'b0; | |
| mst_req_o.aw_valid = 1'b0; | |
| end | |
| end | |
| enum logic { Idle, Invalidating } state_d, state_q; | |
| always_comb begin : inval_fsm | |
| state_d = state_q; | |
| aw_fifo_pop = 1'b0; | |
| inval_offset_d = inval_offset_q; | |
| unique case (state_q) | |
| Idle: begin | |
| if (!aw_fifo_empty) begin | |
| if (inval_ready_i) begin | |
| if ((L1LineWidth - aw_fifo_data.addr[idx_width(L1LineWidth)-1:0]) < ((aw_fifo_data.len + 1) << aw_fifo_data.size)) begin | |
| state_d = Invalidating; | |
| inval_offset_d = L1LineWidth - aw_fifo_data.addr[idx_width(L1LineWidth)-1:0]; | |
| end else begin | |
| aw_fifo_pop = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| Invalidating: begin | |
| if (inval_ready_i) begin | |
| inval_offset_d = inval_offset_q + L1LineWidth; | |
| if (inval_offset_d >= ((aw_fifo_data.len + 1) << aw_fifo_data.size)) begin | |
| state_d = Idle; | |
| inval_offset_d = '0; | |
| aw_fifo_pop = 1'b1; | |
| end | |
| end | |
| end | |
| endcase | |
| end | |
| always_ff @(posedge clk_i or negedge rst_ni) begin | |
| if (!rst_ni) begin | |
| state_q <= Idle; | |
| inval_offset_q <= '0; | |
| end else begin | |
| state_q <= state_d; | |
| inval_offset_q <= inval_offset_d; | |
| end | |
| end | |
| fifo_v3 #( | |
| .FALL_THROUGH ( 1'b1 ), | |
| .DEPTH ( MaxTxns ), | |
| .dtype ( aw_chan_t ) | |
| ) i_aw_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .full_o ( aw_fifo_full ), | |
| .empty_o ( aw_fifo_empty ), | |
| .usage_o ( ), | |
| .data_i ( slv_req_i.aw ), | |
| .push_i ( aw_fifo_push ), | |
| .data_o ( aw_fifo_data ), | |
| .pop_i ( aw_fifo_pop ) | |
| ); | |
| endmodule : axi_inval_filter | |
| `begin_keywords "1800-2023" | |
| module axi_isolate #( | |
| parameter int unsigned NumPending = 32'd16, | |
| parameter bit TerminateTransaction = 1'b0, | |
| parameter bit AtopSupport = 1'b1, | |
| parameter int signed AxiAddrWidth = 32'd0, | |
| parameter int signed AxiDataWidth = 32'd0, | |
| parameter int signed AxiIdWidth = 32'd0, | |
| parameter int signed AxiUserWidth = 32'd0, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i, | |
| input logic isolate_i, | |
| output logic isolated_o | |
| ); | |
| typedef logic [AxiIdWidth-1:0] id_t; | |
| typedef logic [AxiAddrWidth-1:0] addr_t; | |
| typedef logic [AxiDataWidth-1:0] data_t; | |
| typedef logic [AxiDataWidth/8-1:0] strb_t; | |
| typedef logic [AxiUserWidth-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| axi_req_t [1:0] demux_req; | |
| axi_resp_t [1:0] demux_rsp; | |
| if (TerminateTransaction) begin | |
| axi_demux #( | |
| .AxiIdWidth ( AxiIdWidth ), | |
| .AtopSupport ( AtopSupport ), | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .NoMstPorts ( 2 ), | |
| .MaxTrans ( NumPending ), | |
| .AxiLookBits ( 1 ), | |
| .UniqueIds ( 1'b0 ), | |
| .SpillAw ( 1'b0 ), | |
| .SpillW ( 1'b0 ), | |
| .SpillB ( 1'b0 ), | |
| .SpillAr ( 1'b0 ), | |
| .SpillR ( 1'b0 ) | |
| ) i_axi_demux ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i ( 1'b0 ), | |
| .slv_req_i, | |
| .slv_aw_select_i ( isolated_o ), | |
| .slv_ar_select_i ( isolated_o ), | |
| .slv_resp_o, | |
| .mst_reqs_o ( demux_req ), | |
| .mst_resps_i ( demux_rsp ) | |
| ); | |
| axi_err_slv #( | |
| .AxiIdWidth ( AxiIdWidth ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .Resp ( axi_pkg::RESP_DECERR ), | |
| .RespData ( 'h1501A7ED ), | |
| .ATOPs ( AtopSupport ), | |
| .MaxTrans ( 1 ) | |
| ) i_axi_err_slv ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i ( 1'b0 ), | |
| .slv_req_i ( demux_req[1] ), | |
| .slv_resp_o ( demux_rsp[1] ) | |
| ); | |
| end else begin | |
| assign demux_req[0] = slv_req_i; | |
| assign slv_resp_o = demux_rsp[0]; | |
| assign demux_req[1] = '0; | |
| assign demux_rsp[1] = '0; | |
| end | |
| axi_isolate_inner #( | |
| .NumPending ( NumPending ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ) | |
| ) i_axi_isolate ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( demux_req[0] ), | |
| .slv_resp_o ( demux_rsp[0] ), | |
| .mst_req_o, | |
| .mst_resp_i, | |
| .isolate_i, | |
| .isolated_o | |
| ); | |
| endmodule | |
| module axi_isolate_inner #( | |
| parameter int unsigned NumPending = 32'd16, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_req_t slv_req_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i, | |
| input logic isolate_i, | |
| output logic isolated_o | |
| ); | |
| localparam int unsigned CounterWidth = $clog2(NumPending + 32'd1) + 32'd1; | |
| typedef logic [CounterWidth-1:0] cnt_t; | |
| typedef enum logic [1:0] { | |
| Normal, | |
| Hold, | |
| Drain, | |
| Isolate | |
| } isolate_state_e; | |
| isolate_state_e state_aw_d, state_aw_q, state_ar_d, state_ar_q; | |
| logic update_aw_state, update_ar_state; | |
| cnt_t pending_aw_d, pending_aw_q; | |
| logic update_aw_cnt; | |
| cnt_t pending_w_d, pending_w_q; | |
| logic update_w_cnt, connect_w; | |
| cnt_t pending_ar_d, pending_ar_q; | |
| logic update_ar_cnt; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| pending_aw_q <= ('0); | |
| end else begin | |
| if (update_aw_cnt) begin | |
| pending_aw_q <= (pending_aw_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| pending_w_q <= ('0); | |
| end else begin | |
| if (update_w_cnt) begin | |
| pending_w_q <= (pending_w_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| pending_ar_q <= ('0); | |
| end else begin | |
| if (update_ar_cnt) begin | |
| pending_ar_q <= (pending_ar_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| state_aw_q <= (Isolate); | |
| end else begin | |
| if (update_aw_state) begin | |
| state_aw_q <= (state_aw_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| state_ar_q <= (Isolate); | |
| end else begin | |
| if (update_ar_state) begin | |
| state_ar_q <= (state_ar_d); | |
| end | |
| end | |
| end | |
| always_comb begin | |
| pending_aw_d = pending_aw_q; | |
| update_aw_cnt = 1'b0; | |
| pending_w_d = pending_w_q; | |
| update_w_cnt = 1'b0; | |
| connect_w = 1'b0; | |
| pending_ar_d = pending_ar_q; | |
| update_ar_cnt = 1'b0; | |
| if (mst_req_o.aw_valid && (state_aw_q == Normal)) begin | |
| pending_aw_d++; | |
| update_aw_cnt = 1'b1; | |
| pending_w_d++; | |
| update_w_cnt = 1'b1; | |
| connect_w = 1'b1; | |
| if (mst_req_o.aw.atop[axi_pkg::ATOP_R_RESP]) begin | |
| pending_ar_d++; | |
| update_ar_cnt = 1'b1; | |
| end | |
| end | |
| if (mst_req_o.w_valid && mst_resp_i.w_ready && mst_req_o.w.last) begin | |
| pending_w_d--; | |
| update_w_cnt = 1'b1; | |
| end | |
| if (mst_resp_i.b_valid && mst_req_o.b_ready) begin | |
| pending_aw_d--; | |
| update_aw_cnt = 1'b1; | |
| end | |
| if (mst_req_o.ar_valid && (state_ar_q == Normal)) begin | |
| pending_ar_d++; | |
| update_ar_cnt = 1'b1; | |
| end | |
| if (mst_resp_i.r_valid && mst_req_o.r_ready && mst_resp_i.r.last) begin | |
| pending_ar_d--; | |
| update_ar_cnt = 1'b1; | |
| end | |
| end | |
| always_comb begin | |
| state_aw_d = state_aw_q; | |
| update_aw_state = 1'b0; | |
| state_ar_d = state_ar_q; | |
| update_ar_state = 1'b0; | |
| mst_req_o = slv_req_i; | |
| slv_resp_o = mst_resp_i; | |
| unique case (state_aw_q) | |
| Normal: begin | |
| if (pending_aw_q >= cnt_t'(NumPending) || pending_ar_q >= cnt_t'(2*NumPending) | |
| || (pending_w_q >= cnt_t'(NumPending))) begin | |
| mst_req_o.aw_valid = 1'b0; | |
| slv_resp_o.aw_ready = 1'b0; | |
| if (isolate_i) begin | |
| state_aw_d = Drain; | |
| update_aw_state = 1'b1; | |
| end | |
| end else begin | |
| if (slv_req_i.aw_valid && !mst_resp_i.aw_ready) begin | |
| state_aw_d = Hold; | |
| update_aw_state = 1'b1; | |
| end else begin | |
| if (isolate_i) begin | |
| state_aw_d = Drain; | |
| update_aw_state = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| Hold: begin | |
| mst_req_o.aw_valid = 1'b1; | |
| if (mst_resp_i.aw_ready) begin | |
| update_aw_state = 1'b1; | |
| state_aw_d = isolate_i ? Drain : Normal; | |
| end | |
| end | |
| Drain: begin | |
| mst_req_o.aw = '0; | |
| mst_req_o.aw_valid = 1'b0; | |
| slv_resp_o.aw_ready = 1'b0; | |
| if (pending_aw_q == '0) begin | |
| state_aw_d = Isolate; | |
| update_aw_state = 1'b1; | |
| end | |
| end | |
| Isolate: begin | |
| mst_req_o.aw = '0; | |
| mst_req_o.aw_valid = 1'b0; | |
| slv_resp_o.aw_ready = 1'b0; | |
| slv_resp_o.b = '0; | |
| slv_resp_o.b_valid = 1'b0; | |
| mst_req_o.b_ready = 1'b0; | |
| if (!isolate_i) begin | |
| state_aw_d = Normal; | |
| update_aw_state = 1'b1; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| if ((pending_w_q == '0) && !connect_w ) begin | |
| mst_req_o.w = '0; | |
| mst_req_o.w_valid = 1'b0; | |
| slv_resp_o.w_ready = 1'b0; | |
| end | |
| unique case (state_ar_q) | |
| Normal: begin | |
| if (pending_ar_q >= NumPending) begin | |
| mst_req_o.ar_valid = 1'b0; | |
| slv_resp_o.ar_ready = 1'b0; | |
| if (isolate_i) begin | |
| state_ar_d = Drain; | |
| update_ar_state = 1'b1; | |
| end | |
| end else begin | |
| if (slv_req_i.ar_valid && !mst_resp_i.ar_ready) begin | |
| state_ar_d = Hold; | |
| update_ar_state = 1'b1; | |
| end else begin | |
| if (isolate_i) begin | |
| state_ar_d = Drain; | |
| update_ar_state = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| Hold: begin | |
| mst_req_o.ar_valid = 1'b1; | |
| if (mst_resp_i.ar_ready) begin | |
| update_ar_state = 1'b1; | |
| state_ar_d = isolate_i ? Drain : Normal; | |
| end | |
| end | |
| Drain: begin | |
| mst_req_o.ar = '0; | |
| mst_req_o.ar_valid = 1'b0; | |
| slv_resp_o.ar_ready = 1'b0; | |
| if (pending_ar_q == '0) begin | |
| state_ar_d = Isolate; | |
| update_ar_state = 1'b1; | |
| end | |
| end | |
| Isolate: begin | |
| mst_req_o.ar = '0; | |
| mst_req_o.ar_valid = 1'b0; | |
| slv_resp_o.ar_ready = 1'b0; | |
| slv_resp_o.r = '0; | |
| slv_resp_o.r_valid = 1'b0; | |
| mst_req_o.r_ready = 1'b0; | |
| if (!isolate_i) begin | |
| state_ar_d = Normal; | |
| update_ar_state = 1'b1; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| assign isolated_o = (state_aw_q == Isolate && state_ar_q == Isolate); | |
| endmodule | |
| module axi_isolate_intf #( | |
| parameter int unsigned NUM_PENDING = 32'd16, | |
| parameter bit TERMINATE_TRANSACTION = 1'b0, | |
| parameter bit ATOP_SUPPORT = 1'b1, | |
| parameter int unsigned AXI_ID_WIDTH = 32'd0, | |
| parameter int unsigned AXI_ADDR_WIDTH = 32'd0, | |
| parameter int unsigned AXI_DATA_WIDTH = 32'd0, | |
| parameter int unsigned AXI_USER_WIDTH = 32'd0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| AXI_BUS.Slave slv, | |
| AXI_BUS.Master mst, | |
| input logic isolate_i, | |
| output logic isolated_o | |
| ); | |
| typedef logic [AXI_ID_WIDTH-1:0] id_t; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef logic [AXI_USER_WIDTH-1:0] user_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| axi_pkg::atop_t atop; | |
| user_t user; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| logic last; | |
| user_t user; | |
| } w_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| axi_pkg::resp_t resp; | |
| user_t user; | |
| } b_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| addr_t addr; | |
| axi_pkg::len_t len; | |
| axi_pkg::size_t size; | |
| axi_pkg::burst_t burst; | |
| logic lock; | |
| axi_pkg::cache_t cache; | |
| axi_pkg::prot_t prot; | |
| axi_pkg::qos_t qos; | |
| axi_pkg::region_t region; | |
| user_t user; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| id_t id; | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| logic last; | |
| user_t user; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic ar_ready; | |
| logic w_ready; | |
| logic b_valid; | |
| b_chan_t b; | |
| logic r_valid; | |
| r_chan_t r; | |
| } axi_resp_t; | |
| axi_req_t slv_req, mst_req; | |
| axi_resp_t slv_resp, mst_resp; | |
| assign slv_req.aw.id = slv.aw_id; | |
| assign slv_req.aw.addr = slv.aw_addr; | |
| assign slv_req.aw.len = slv.aw_len; | |
| assign slv_req.aw.size = slv.aw_size; | |
| assign slv_req.aw.burst = slv.aw_burst; | |
| assign slv_req.aw.lock = slv.aw_lock; | |
| assign slv_req.aw.cache = slv.aw_cache; | |
| assign slv_req.aw.prot = slv.aw_prot; | |
| assign slv_req.aw.qos = slv.aw_qos; | |
| assign slv_req.aw.region = slv.aw_region; | |
| assign slv_req.aw.atop = slv.aw_atop; | |
| assign slv_req.aw.user = slv.aw_user; | |
| assign slv_req.aw_valid = slv.aw_valid; | |
| assign slv_req.w.data = slv.w_data; | |
| assign slv_req.w.strb = slv.w_strb; | |
| assign slv_req.w.last = slv.w_last; | |
| assign slv_req.w.user = slv.w_user; | |
| assign slv_req.w_valid = slv.w_valid; | |
| assign slv_req.b_ready = slv.b_ready; | |
| assign slv_req.ar.id = slv.ar_id; | |
| assign slv_req.ar.addr = slv.ar_addr; | |
| assign slv_req.ar.len = slv.ar_len; | |
| assign slv_req.ar.size = slv.ar_size; | |
| assign slv_req.ar.burst = slv.ar_burst; | |
| assign slv_req.ar.lock = slv.ar_lock; | |
| assign slv_req.ar.cache = slv.ar_cache; | |
| assign slv_req.ar.prot = slv.ar_prot; | |
| assign slv_req.ar.qos = slv.ar_qos; | |
| assign slv_req.ar.region = slv.ar_region; | |
| assign slv_req.ar.user = slv.ar_user; | |
| assign slv_req.ar_valid = slv.ar_valid; | |
| assign slv_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = slv_resp.aw_ready; | |
| assign slv.ar_ready = slv_resp.ar_ready; | |
| assign slv.w_ready = slv_resp.w_ready; | |
| assign slv.b_valid = slv_resp.b_valid; | |
| assign slv.b_id = slv_resp.b.id; | |
| assign slv.b_resp = slv_resp.b.resp; | |
| assign slv.b_user = slv_resp.b.user; | |
| assign slv.r_valid = slv_resp.r_valid; | |
| assign slv.r_id = slv_resp.r.id; | |
| assign slv.r_data = slv_resp.r.data; | |
| assign slv.r_resp = slv_resp.r.resp; | |
| assign slv.r_last = slv_resp.r.last; | |
| assign slv.r_user = slv_resp.r.user; | |
| assign mst.aw_id = mst_req.aw.id; | |
| assign mst.aw_addr = mst_req.aw.addr; | |
| assign mst.aw_len = mst_req.aw.len; | |
| assign mst.aw_size = mst_req.aw.size; | |
| assign mst.aw_burst = mst_req.aw.burst; | |
| assign mst.aw_lock = mst_req.aw.lock; | |
| assign mst.aw_cache = mst_req.aw.cache; | |
| assign mst.aw_prot = mst_req.aw.prot; | |
| assign mst.aw_qos = mst_req.aw.qos; | |
| assign mst.aw_region = mst_req.aw.region; | |
| assign mst.aw_atop = mst_req.aw.atop; | |
| assign mst.aw_user = mst_req.aw.user; | |
| assign mst.aw_valid = mst_req.aw_valid; | |
| assign mst.w_data = mst_req.w.data; | |
| assign mst.w_strb = mst_req.w.strb; | |
| assign mst.w_last = mst_req.w.last; | |
| assign mst.w_user = mst_req.w.user; | |
| assign mst.w_valid = mst_req.w_valid; | |
| assign mst.b_ready = mst_req.b_ready; | |
| assign mst.ar_id = mst_req.ar.id; | |
| assign mst.ar_addr = mst_req.ar.addr; | |
| assign mst.ar_len = mst_req.ar.len; | |
| assign mst.ar_size = mst_req.ar.size; | |
| assign mst.ar_burst = mst_req.ar.burst; | |
| assign mst.ar_lock = mst_req.ar.lock; | |
| assign mst.ar_cache = mst_req.ar.cache; | |
| assign mst.ar_prot = mst_req.ar.prot; | |
| assign mst.ar_qos = mst_req.ar.qos; | |
| assign mst.ar_region = mst_req.ar.region; | |
| assign mst.ar_user = mst_req.ar.user; | |
| assign mst.ar_valid = mst_req.ar_valid; | |
| assign mst.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = mst.aw_ready; | |
| assign mst_resp.ar_ready = mst.ar_ready; | |
| assign mst_resp.w_ready = mst.w_ready; | |
| assign mst_resp.b_valid = mst.b_valid; | |
| assign mst_resp.b.id = mst.b_id; | |
| assign mst_resp.b.resp = mst.b_resp; | |
| assign mst_resp.b.user = mst.b_user; | |
| assign mst_resp.r_valid = mst.r_valid; | |
| assign mst_resp.r.id = mst.r_id; | |
| assign mst_resp.r.data = mst.r_data; | |
| assign mst_resp.r.resp = mst.r_resp; | |
| assign mst_resp.r.last = mst.r_last; | |
| assign mst_resp.r.user = mst.r_user; | |
| axi_isolate #( | |
| .NumPending ( NUM_PENDING ), | |
| .TerminateTransaction ( TERMINATE_TRANSACTION ), | |
| .AtopSupport ( ATOP_SUPPORT ), | |
| .AxiAddrWidth ( AXI_ADDR_WIDTH ), | |
| .AxiDataWidth ( AXI_DATA_WIDTH ), | |
| .AxiIdWidth ( AXI_ID_WIDTH ), | |
| .AxiUserWidth ( AXI_USER_WIDTH ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ) | |
| ) i_axi_isolate ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_req ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_req_o ( mst_req ), | |
| .mst_resp_i ( mst_resp ), | |
| .isolate_i, | |
| .isolated_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_join_intf ( | |
| AXI_BUS.Slave in, | |
| AXI_BUS.Master out | |
| ); | |
| assign out.aw_id = in.aw_id; | |
| assign out.aw_addr = in.aw_addr; | |
| assign out.aw_len = in.aw_len; | |
| assign out.aw_size = in.aw_size; | |
| assign out.aw_burst = in.aw_burst; | |
| assign out.aw_lock = in.aw_lock; | |
| assign out.aw_cache = in.aw_cache; | |
| assign out.aw_prot = in.aw_prot; | |
| assign out.aw_qos = in.aw_qos; | |
| assign out.aw_region = in.aw_region; | |
| assign out.aw_atop = in.aw_atop; | |
| assign out.aw_user = in.aw_user; | |
| assign out.aw_valid = in.aw_valid; | |
| assign in.aw_ready = out.aw_ready; | |
| assign out.w_data = in.w_data; | |
| assign out.w_strb = in.w_strb; | |
| assign out.w_last = in.w_last; | |
| assign out.w_user = in.w_user; | |
| assign out.w_valid = in.w_valid; | |
| assign in.w_ready = out.w_ready; | |
| assign in.b_id = out.b_id; | |
| assign in.b_resp = out.b_resp; | |
| assign in.b_user = out.b_user; | |
| assign in.b_valid = out.b_valid; | |
| assign out.b_ready = in.b_ready; | |
| assign out.ar_id = in.ar_id; | |
| assign out.ar_addr = in.ar_addr; | |
| assign out.ar_len = in.ar_len; | |
| assign out.ar_size = in.ar_size; | |
| assign out.ar_burst = in.ar_burst; | |
| assign out.ar_lock = in.ar_lock; | |
| assign out.ar_cache = in.ar_cache; | |
| assign out.ar_prot = in.ar_prot; | |
| assign out.ar_qos = in.ar_qos; | |
| assign out.ar_region = in.ar_region; | |
| assign out.ar_user = in.ar_user; | |
| assign out.ar_valid = in.ar_valid; | |
| assign in.ar_ready = out.ar_ready; | |
| assign in.r_id = out.r_id; | |
| assign in.r_data = out.r_data; | |
| assign in.r_resp = out.r_resp; | |
| assign in.r_last = out.r_last; | |
| assign in.r_user = out.r_user; | |
| assign in.r_valid = out.r_valid; | |
| assign out.r_ready = in.r_ready; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_demux #( | |
| parameter type aw_chan_t = logic, | |
| parameter type w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic, | |
| parameter int unsigned NoMstPorts = 32'd0, | |
| parameter int unsigned MaxTrans = 32'd0, | |
| parameter bit FallThrough = 1'b0, | |
| parameter bit SpillAw = 1'b1, | |
| parameter bit SpillW = 1'b0, | |
| parameter bit SpillB = 1'b0, | |
| parameter bit SpillAr = 1'b1, | |
| parameter bit SpillR = 1'b0, | |
| parameter type select_t = logic [$clog2(NoMstPorts)-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| input axi_req_t slv_req_i, | |
| input select_t slv_aw_select_i, | |
| input select_t slv_ar_select_i, | |
| output axi_resp_t slv_resp_o, | |
| output axi_req_t [NoMstPorts-1:0] mst_reqs_o, | |
| input axi_resp_t [NoMstPorts-1:0] mst_resps_i | |
| ); | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| select_t select; | |
| } aw_chan_select_t; | |
| typedef struct packed { | |
| ar_chan_t ar; | |
| select_t select; | |
| } ar_chan_select_t; | |
| if (NoMstPorts == 32'd1) begin : gen_no_demux | |
| spill_register #( | |
| .T ( aw_chan_t ), | |
| .Bypass ( ~SpillAw ) | |
| ) i_aw_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.aw_valid ), | |
| .ready_o ( slv_resp_o.aw_ready ), | |
| .data_i ( slv_req_i.aw ), | |
| .valid_o ( mst_reqs_o[0].aw_valid ), | |
| .ready_i ( mst_resps_i[0].aw_ready ), | |
| .data_o ( mst_reqs_o[0].aw ) | |
| ); | |
| spill_register #( | |
| .T ( w_chan_t ), | |
| .Bypass ( ~SpillW ) | |
| ) i_w_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.w_valid ), | |
| .ready_o ( slv_resp_o.w_ready ), | |
| .data_i ( slv_req_i.w ), | |
| .valid_o ( mst_reqs_o[0].w_valid ), | |
| .ready_i ( mst_resps_i[0].w_ready ), | |
| .data_o ( mst_reqs_o[0].w ) | |
| ); | |
| spill_register #( | |
| .T ( b_chan_t ), | |
| .Bypass ( ~SpillB ) | |
| ) i_b_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_resps_i[0].b_valid ), | |
| .ready_o ( mst_reqs_o[0].b_ready ), | |
| .data_i ( mst_resps_i[0].b ), | |
| .valid_o ( slv_resp_o.b_valid ), | |
| .ready_i ( slv_req_i.b_ready ), | |
| .data_o ( slv_resp_o.b ) | |
| ); | |
| spill_register #( | |
| .T ( ar_chan_t ), | |
| .Bypass ( ~SpillAr ) | |
| ) i_ar_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.ar_valid ), | |
| .ready_o ( slv_resp_o.ar_ready ), | |
| .data_i ( slv_req_i.ar ), | |
| .valid_o ( mst_reqs_o[0].ar_valid ), | |
| .ready_i ( mst_resps_i[0].ar_ready ), | |
| .data_o ( mst_reqs_o[0].ar ) | |
| ); | |
| spill_register #( | |
| .T ( r_chan_t ), | |
| .Bypass ( ~SpillR ) | |
| ) i_r_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_resps_i[0].r_valid ), | |
| .ready_o ( mst_reqs_o[0].r_ready ), | |
| .data_i ( mst_resps_i[0].r ), | |
| .valid_o ( slv_resp_o.r_valid ), | |
| .ready_i ( slv_req_i.r_ready ), | |
| .data_o ( slv_resp_o.r ) | |
| ); | |
| end else begin : gen_demux | |
| aw_chan_select_t slv_aw_chan; | |
| logic slv_aw_valid, slv_aw_ready; | |
| logic [NoMstPorts-1:0] mst_aw_valids, mst_aw_readies; | |
| logic lock_aw_valid_d, lock_aw_valid_q, load_aw_lock; | |
| logic w_fifo_push, w_fifo_pop; | |
| logic w_fifo_full, w_fifo_empty; | |
| w_chan_t slv_w_chan; | |
| select_t w_select; | |
| logic slv_w_valid, slv_w_ready; | |
| logic b_fifo_pop; | |
| logic b_fifo_full, b_fifo_empty; | |
| b_chan_t slv_b_chan; | |
| select_t b_select; | |
| logic slv_b_valid, slv_b_ready; | |
| ar_chan_select_t slv_ar_chan; | |
| logic slv_ar_valid, slv_ar_ready; | |
| logic r_fifo_push, r_fifo_pop; | |
| logic r_fifo_full, r_fifo_empty; | |
| r_chan_t slv_r_chan; | |
| select_t r_select; | |
| logic slv_r_valid, slv_r_ready; | |
| typedef aw_chan_select_t aw_chan_select_flat_t; | |
| aw_chan_select_flat_t slv_aw_chan_select_in_flat, | |
| slv_aw_chan_select_out_flat; | |
| assign slv_aw_chan_select_in_flat = {slv_req_i.aw, slv_aw_select_i}; | |
| spill_register #( | |
| .T ( aw_chan_select_flat_t ), | |
| .Bypass ( ~SpillAw ) | |
| ) i_aw_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.aw_valid ), | |
| .ready_o ( slv_resp_o.aw_ready ), | |
| .data_i ( slv_aw_chan_select_in_flat ), | |
| .valid_o ( slv_aw_valid ), | |
| .ready_i ( slv_aw_ready ), | |
| .data_o ( slv_aw_chan_select_out_flat ) | |
| ); | |
| assign slv_aw_chan = slv_aw_chan_select_out_flat; | |
| for (genvar i = 0; i < NoMstPorts; i++) begin : gen_mst_aw | |
| assign mst_reqs_o[i].aw = slv_aw_chan.aw; | |
| assign mst_reqs_o[i].aw_valid = mst_aw_valids[i]; | |
| assign mst_aw_readies[i] = mst_resps_i[i].aw_ready; | |
| end | |
| always_comb begin | |
| lock_aw_valid_d = lock_aw_valid_q; | |
| load_aw_lock = 1'b0; | |
| slv_aw_ready = 1'b0; | |
| mst_aw_valids = '0; | |
| w_fifo_push = 1'b0; | |
| if (lock_aw_valid_q) begin | |
| mst_aw_valids[slv_aw_chan.select] = 1'b1; | |
| if (mst_aw_readies[slv_aw_chan.select]) begin | |
| slv_aw_ready = 1'b1; | |
| lock_aw_valid_d = 1'b0; | |
| load_aw_lock = 1'b1; | |
| end | |
| end else begin | |
| if (!w_fifo_full && slv_aw_valid) begin | |
| w_fifo_push = 1'b1; | |
| mst_aw_valids[slv_aw_chan.select] = 1'b1; | |
| if (mst_aw_readies[slv_aw_chan.select]) begin | |
| slv_aw_ready = 1'b1; | |
| end else begin | |
| lock_aw_valid_d = 1'b1; | |
| load_aw_lock = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| lock_aw_valid_q <= ('0); | |
| end else begin | |
| if (load_aw_lock) begin | |
| lock_aw_valid_q <= (lock_aw_valid_d); | |
| end | |
| end | |
| end | |
| fifo_v3 #( | |
| .FALL_THROUGH( FallThrough ), | |
| .DEPTH ( MaxTrans ), | |
| .dtype ( select_t ) | |
| ) i_w_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( test_i ), | |
| .full_o ( w_fifo_full ), | |
| .empty_o ( w_fifo_empty ), | |
| .usage_o ( ), | |
| .data_i ( slv_aw_chan.select ), | |
| .push_i ( w_fifo_push ), | |
| .data_o ( w_select ), | |
| .pop_i ( w_fifo_pop ) | |
| ); | |
| spill_register #( | |
| .T ( w_chan_t ), | |
| .Bypass ( ~SpillW ) | |
| ) i_w_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.w_valid ), | |
| .ready_o ( slv_resp_o.w_ready ), | |
| .data_i ( slv_req_i.w ), | |
| .valid_o ( slv_w_valid ), | |
| .ready_i ( slv_w_ready ), | |
| .data_o ( slv_w_chan ) | |
| ); | |
| for (genvar i = 0; i < NoMstPorts; i++) begin : gen_mst_w | |
| assign mst_reqs_o[i].w = slv_w_chan; | |
| assign mst_reqs_o[i].w_valid = ~w_fifo_empty & ~b_fifo_full & | |
| slv_w_valid & (w_select == select_t'(i)); | |
| end | |
| assign slv_w_ready = ~w_fifo_empty & ~b_fifo_full & mst_resps_i[w_select].w_ready; | |
| assign w_fifo_pop = slv_w_valid & slv_w_ready; | |
| fifo_v3 #( | |
| .FALL_THROUGH( FallThrough ), | |
| .DEPTH ( MaxTrans ), | |
| .dtype ( select_t ) | |
| ) i_b_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( test_i ), | |
| .full_o ( b_fifo_full ), | |
| .empty_o ( b_fifo_empty ), | |
| .usage_o ( ), | |
| .data_i ( w_select ), | |
| .push_i ( w_fifo_pop ), | |
| .data_o ( b_select ), | |
| .pop_i ( b_fifo_pop ) | |
| ); | |
| spill_register #( | |
| .T ( b_chan_t ), | |
| .Bypass ( ~SpillB ) | |
| ) i_b_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_b_valid ), | |
| .ready_o ( slv_b_ready ), | |
| .data_i ( slv_b_chan ), | |
| .valid_o ( slv_resp_o.b_valid ), | |
| .ready_i ( slv_req_i.b_ready ), | |
| .data_o ( slv_resp_o.b ) | |
| ); | |
| assign slv_b_chan = (!b_fifo_empty) ? mst_resps_i[b_select].b : '0; | |
| assign slv_b_valid = ~b_fifo_empty & mst_resps_i[b_select].b_valid; | |
| for (genvar i = 0; i < NoMstPorts; i++) begin : gen_mst_b | |
| assign mst_reqs_o[i].b_ready = ~b_fifo_empty & slv_b_ready & (b_select == select_t'(i)); | |
| end | |
| assign b_fifo_pop = slv_b_valid & slv_b_ready; | |
| typedef ar_chan_select_t ar_chan_select_flat_t; | |
| ar_chan_select_flat_t slv_ar_chan_select_in_flat, | |
| slv_ar_chan_select_out_flat; | |
| assign slv_ar_chan_select_in_flat = {slv_req_i.ar, slv_ar_select_i}; | |
| spill_register #( | |
| .T ( ar_chan_select_flat_t ), | |
| .Bypass ( ~SpillAr ) | |
| ) i_ar_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_req_i.ar_valid ), | |
| .ready_o ( slv_resp_o.ar_ready ), | |
| .data_i ( slv_ar_chan_select_in_flat ), | |
| .valid_o ( slv_ar_valid ), | |
| .ready_i ( slv_ar_ready ), | |
| .data_o ( slv_ar_chan_select_out_flat ) | |
| ); | |
| assign slv_ar_chan = slv_ar_chan_select_out_flat; | |
| for (genvar i = 0; i < NoMstPorts; i++) begin : gen_mst_ar | |
| assign mst_reqs_o[i].ar = slv_ar_chan.ar; | |
| assign mst_reqs_o[i].ar_valid = ~r_fifo_full & slv_ar_valid & | |
| (slv_ar_chan.select == select_t'(i)); | |
| end | |
| assign slv_ar_ready = ~r_fifo_full & mst_resps_i[slv_ar_chan.select].ar_ready; | |
| assign r_fifo_push = slv_ar_valid & slv_ar_ready; | |
| fifo_v3 #( | |
| .FALL_THROUGH( FallThrough ), | |
| .DEPTH ( MaxTrans ), | |
| .dtype ( select_t ) | |
| ) i_r_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( test_i ), | |
| .full_o ( r_fifo_full ), | |
| .empty_o ( r_fifo_empty ), | |
| .usage_o ( ), | |
| .data_i ( slv_ar_chan.select ), | |
| .push_i ( r_fifo_push ), | |
| .data_o ( r_select ), | |
| .pop_i ( r_fifo_pop ) | |
| ); | |
| spill_register #( | |
| .T ( r_chan_t ), | |
| .Bypass ( ~SpillR ) | |
| ) i_r_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_r_valid ), | |
| .ready_o ( slv_r_ready ), | |
| .data_i ( slv_r_chan ), | |
| .valid_o ( slv_resp_o.r_valid ), | |
| .ready_i ( slv_req_i.r_ready ), | |
| .data_o ( slv_resp_o.r ) | |
| ); | |
| always_comb begin | |
| slv_r_chan = '0; | |
| slv_r_valid = '0; | |
| if (!r_fifo_empty) begin | |
| slv_r_chan = mst_resps_i[r_select].r; | |
| slv_r_valid = mst_resps_i[r_select].r_valid; | |
| end | |
| end | |
| for (genvar i = 0; i < NoMstPorts; i++) begin : gen_mst_r | |
| assign mst_reqs_o[i].r_ready = ~r_fifo_empty & slv_r_ready & (r_select == select_t'(i)); | |
| end | |
| assign r_fifo_pop = slv_r_valid & slv_r_ready; | |
| end | |
| endmodule | |
| module axi_lite_demux_intf #( | |
| parameter int unsigned AxiAddrWidth = 32'd0, | |
| parameter int unsigned AxiDataWidth = 32'd0, | |
| parameter int unsigned NoMstPorts = 32'd0, | |
| parameter int unsigned MaxTrans = 32'd0, | |
| parameter bit FallThrough = 1'b0, | |
| parameter bit SpillAw = 1'b1, | |
| parameter bit SpillW = 1'b0, | |
| parameter bit SpillB = 1'b0, | |
| parameter bit SpillAr = 1'b1, | |
| parameter bit SpillR = 1'b0, | |
| parameter type select_t = logic [$clog2(NoMstPorts)-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| input select_t slv_aw_select_i, | |
| input select_t slv_ar_select_i, | |
| AXI_LITE.Slave slv, | |
| AXI_LITE.Master mst [NoMstPorts-1:0] | |
| ); | |
| typedef logic [AxiAddrWidth-1:0] addr_t; | |
| typedef logic [AxiDataWidth-1:0] data_t; | |
| typedef logic [AxiDataWidth/8-1:0] strb_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_t r; | |
| logic r_valid; | |
| } axi_resp_t; | |
| axi_req_t slv_req; | |
| axi_resp_t slv_resp; | |
| axi_req_t [NoMstPorts-1:0] mst_reqs; | |
| axi_resp_t [NoMstPorts-1:0] mst_resps; | |
| assign slv_req.aw.addr = slv.aw_addr; | |
| assign slv_req.aw.prot = slv.aw_prot; | |
| assign slv_req.aw_valid = slv.aw_valid; | |
| assign slv_req.w.data = slv.w_data; | |
| assign slv_req.w.strb = slv.w_strb; | |
| assign slv_req.w_valid = slv.w_valid; | |
| assign slv_req.b_ready = slv.b_ready; | |
| assign slv_req.ar.addr = slv.ar_addr; | |
| assign slv_req.ar.prot = slv.ar_prot; | |
| assign slv_req.ar_valid = slv.ar_valid; | |
| assign slv_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = slv_resp.aw_ready; | |
| assign slv.ar_ready = slv_resp.ar_ready; | |
| assign slv.w_ready = slv_resp.w_ready; | |
| assign slv.b_valid = slv_resp.b_valid; | |
| assign slv.b_resp = slv_resp.b.resp; | |
| assign slv.r_valid = slv_resp.r_valid; | |
| assign slv.r_data = slv_resp.r.data; | |
| assign slv.r_resp = slv_resp.r.resp; | |
| for (genvar i = 0; i < NoMstPorts; i++) begin : gen_assign_mst_ports | |
| assign mst[i].aw_addr = mst_reqs[i].aw.addr; | |
| assign mst[i].aw_prot = mst_reqs[i].aw.prot; | |
| assign mst[i].aw_valid = mst_reqs[i].aw_valid; | |
| assign mst[i].w_data = mst_reqs[i].w.data; | |
| assign mst[i].w_strb = mst_reqs[i].w.strb; | |
| assign mst[i].w_valid = mst_reqs[i].w_valid; | |
| assign mst[i].b_ready = mst_reqs[i].b_ready; | |
| assign mst[i].ar_addr = mst_reqs[i].ar.addr; | |
| assign mst[i].ar_prot = mst_reqs[i].ar.prot; | |
| assign mst[i].ar_valid = mst_reqs[i].ar_valid; | |
| assign mst[i].r_ready = mst_reqs[i].r_ready; | |
| assign mst_resps[i].aw_ready = mst[i].aw_ready; | |
| assign mst_resps[i].ar_ready = mst[i].ar_ready; | |
| assign mst_resps[i].w_ready = mst[i].w_ready; | |
| assign mst_resps[i].b_valid = mst[i].b_valid; | |
| assign mst_resps[i].b.resp = mst[i].b_resp; | |
| assign mst_resps[i].r_valid = mst[i].r_valid; | |
| assign mst_resps[i].r.data = mst[i].r_data; | |
| assign mst_resps[i].r.resp = mst[i].r_resp; | |
| end | |
| axi_lite_demux #( | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .NoMstPorts ( NoMstPorts ), | |
| .MaxTrans ( MaxTrans ), | |
| .FallThrough ( FallThrough ), | |
| .SpillAw ( SpillAw ), | |
| .SpillW ( SpillW ), | |
| .SpillB ( SpillB ), | |
| .SpillAr ( SpillAr ), | |
| .SpillR ( SpillR ) | |
| ) i_axi_demux ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i, | |
| .slv_req_i ( slv_req ), | |
| .slv_aw_select_i ( slv_aw_select_i ), | |
| .slv_ar_select_i ( slv_ar_select_i ), | |
| .slv_resp_o ( slv_resp ), | |
| .mst_reqs_o ( mst_reqs ), | |
| .mst_resps_i ( mst_resps ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_dw_converter #( | |
| parameter int unsigned AxiAddrWidth = 32'd0, | |
| parameter int unsigned AxiSlvPortDataWidth = 32'd0, | |
| parameter int unsigned AxiMstPortDataWidth = 32'd0, | |
| parameter type axi_lite_aw_t = logic, | |
| parameter type axi_lite_slv_w_t = logic, | |
| parameter type axi_lite_mst_w_t = logic, | |
| parameter type axi_lite_b_t = logic, | |
| parameter type axi_lite_ar_t = logic, | |
| parameter type axi_lite_slv_r_t = logic, | |
| parameter type axi_lite_mst_r_t = logic, | |
| parameter type axi_lite_slv_req_t = logic, | |
| parameter type axi_lite_slv_res_t = logic, | |
| parameter type axi_lite_mst_req_t = logic, | |
| parameter type axi_lite_mst_res_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_lite_slv_req_t slv_req_i, | |
| output axi_lite_slv_res_t slv_res_o, | |
| output axi_lite_mst_req_t mst_req_o, | |
| input axi_lite_mst_res_t mst_res_i | |
| ); | |
| localparam int unsigned AxiSlvPortStrbWidth = AxiSlvPortDataWidth / 32'd8; | |
| localparam int unsigned AxiMstPortStrbWidth = AxiMstPortDataWidth / 32'd8; | |
| typedef logic [AxiAddrWidth-1:0] addr_t; | |
| if (AxiSlvPortDataWidth > AxiMstPortDataWidth) begin : gen_downsizer | |
| localparam int unsigned DownsizeFactor = AxiSlvPortDataWidth / AxiMstPortDataWidth; | |
| localparam int unsigned SelWidth = $clog2(DownsizeFactor); | |
| typedef logic [SelWidth-1:0] sel_t; | |
| localparam int unsigned SelOffset = $clog2(AxiMstPortStrbWidth); | |
| function automatic addr_t out_address(input addr_t address, input sel_t sel); | |
| out_address = address; | |
| out_address[SelOffset+:SelWidth] = sel; | |
| out_address[SelOffset-1:0] = SelOffset'(0); | |
| endfunction : out_address | |
| axi_lite_aw_t aw_chan_spill; | |
| logic aw_chan_spill_valid, aw_chan_spill_ready; | |
| spill_register #( | |
| .T ( axi_lite_aw_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_spill_register_aw ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( slv_req_i.aw_valid ), | |
| .ready_o ( slv_res_o.aw_ready ), | |
| .data_i ( slv_req_i.aw ), | |
| .valid_o ( aw_chan_spill_valid ), | |
| .ready_i ( aw_chan_spill_ready ), | |
| .data_o ( aw_chan_spill ) | |
| ); | |
| sel_t aw_sel_q, aw_sel_d; | |
| logic aw_sel_load; | |
| always_comb begin : proc_aw_chan_oup | |
| mst_req_o.aw = aw_chan_spill; | |
| mst_req_o.aw.addr = out_address(aw_chan_spill.addr, aw_sel_q); | |
| end | |
| assign mst_req_o.aw_valid = aw_chan_spill_valid; | |
| assign aw_chan_spill_ready = mst_res_i.aw_ready & (&aw_sel_q); | |
| assign aw_sel_load = mst_req_o.aw_valid & mst_res_i.aw_ready; | |
| assign aw_sel_d = sel_t'(aw_sel_q + 1'b1); | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| aw_sel_q <= ('0); | |
| end else begin | |
| if (aw_sel_load) begin | |
| aw_sel_q <= (aw_sel_d); | |
| end | |
| end | |
| end | |
| axi_lite_slv_w_t w_chan_spill; | |
| logic w_chan_spill_valid, w_chan_spill_ready; | |
| spill_register #( | |
| .T ( axi_lite_slv_w_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_spill_register_w ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( slv_req_i.w_valid ), | |
| .ready_o ( slv_res_o.w_ready ), | |
| .data_i ( slv_req_i.w ), | |
| .valid_o ( w_chan_spill_valid ), | |
| .ready_i ( w_chan_spill_ready ), | |
| .data_o ( w_chan_spill ) | |
| ); | |
| sel_t w_sel_q, w_sel_d; | |
| logic w_sel_load; | |
| assign mst_req_o.w = axi_lite_mst_w_t'{ | |
| data: w_chan_spill.data[w_sel_q*AxiMstPortDataWidth+:AxiMstPortDataWidth], | |
| strb: w_chan_spill.strb[w_sel_q*AxiMstPortStrbWidth+:AxiMstPortStrbWidth], | |
| default: '0 | |
| }; | |
| assign mst_req_o.w_valid = w_chan_spill_valid; | |
| assign w_chan_spill_ready = mst_res_i.w_ready & (&w_sel_q); | |
| assign w_sel_load = mst_req_o.w_valid & mst_res_i.w_ready; | |
| assign w_sel_d = sel_t'(w_sel_q + 1'b1); | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| w_sel_q <= ('0); | |
| end else begin | |
| if (w_sel_load) begin | |
| w_sel_q <= (w_sel_d); | |
| end | |
| end | |
| end | |
| sel_t b_sel_q, b_sel_d; | |
| axi_pkg::resp_t b_resp_q, b_resp_d; | |
| logic b_resp_load; | |
| assign slv_res_o.b = axi_lite_b_t'{ | |
| resp: b_resp_q | mst_res_i.b.resp, | |
| default: '0 | |
| }; | |
| assign slv_res_o.b_valid = mst_res_i.b_valid & (&b_sel_q); | |
| assign mst_req_o.b_ready = (&b_sel_q) ? slv_req_i.b_ready : 1'b1; | |
| assign b_sel_d = sel_t'(b_sel_q + 1'b1); | |
| assign b_resp_d = (&b_sel_q) ? axi_pkg::RESP_OKAY : (b_resp_q | mst_res_i.b.resp); | |
| assign b_resp_load = mst_res_i.b_valid & mst_req_o.b_ready; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| b_sel_q <= ('0); | |
| end else begin | |
| if (b_resp_load) begin | |
| b_sel_q <= (b_sel_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| b_resp_q <= (axi_pkg::RESP_OKAY); | |
| end else begin | |
| if (b_resp_load) begin | |
| b_resp_q <= (b_resp_d); | |
| end | |
| end | |
| end | |
| axi_lite_ar_t ar_chan_spill; | |
| logic ar_chan_spill_valid, ar_chan_spill_ready; | |
| spill_register #( | |
| .T ( axi_lite_ar_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_spill_register_ar ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( slv_req_i.ar_valid ), | |
| .ready_o ( slv_res_o.ar_ready ), | |
| .data_i ( slv_req_i.ar ), | |
| .valid_o ( ar_chan_spill_valid ), | |
| .ready_i ( ar_chan_spill_ready ), | |
| .data_o ( ar_chan_spill ) | |
| ); | |
| sel_t ar_sel_q, ar_sel_d; | |
| logic ar_sel_load; | |
| always_comb begin : proc_ar_chan_oup | |
| mst_req_o.ar = ar_chan_spill; | |
| mst_req_o.ar.addr = out_address(ar_chan_spill.addr, ar_sel_q); | |
| end | |
| assign mst_req_o.ar_valid = ar_chan_spill_valid; | |
| assign ar_chan_spill_ready = mst_res_i.ar_ready & (&ar_sel_q); | |
| assign ar_sel_load = mst_req_o.ar_valid & mst_res_i.ar_ready; | |
| assign ar_sel_d = sel_t'(ar_sel_q + 1'b1); | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| ar_sel_q <= ('0); | |
| end else begin | |
| if (ar_sel_load) begin | |
| ar_sel_q <= (ar_sel_d); | |
| end | |
| end | |
| end | |
| sel_t r_sel_q, r_sel_d; | |
| logic r_sel_load; | |
| axi_lite_mst_r_t [DownsizeFactor-2:0] r_chan_mst_q; | |
| logic [DownsizeFactor-2:0] r_chan_mst_load; | |
| for (genvar i = 0; unsigned'(i) < (DownsizeFactor-1); i++) begin : gen_r_chan_ff | |
| assign r_chan_mst_load[i] = (sel_t'(i) == r_sel_q) & mst_res_i.r_valid & mst_req_o.r_ready; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| r_chan_mst_q[i] <= (axi_lite_mst_r_t'{default: '0}); | |
| end else begin | |
| if (r_chan_mst_load[i]) begin | |
| r_chan_mst_q[i] <= (mst_res_i.r); | |
| end | |
| end | |
| end | |
| end | |
| assign r_sel_load = mst_res_i.r_valid & mst_req_o.r_ready; | |
| assign r_sel_d = sel_t'(r_sel_q + 1'b1); | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| r_sel_q <= ('0); | |
| end else begin | |
| if (r_sel_load) begin | |
| r_sel_q <= (r_sel_d); | |
| end | |
| end | |
| end | |
| always_comb begin : proc_r_chan_oup | |
| slv_res_o.r = axi_lite_slv_r_t'{ | |
| resp: mst_res_i.r.resp, | |
| default: '0 | |
| }; | |
| for (int unsigned i = 0; i < (DownsizeFactor-1); i++) begin | |
| slv_res_o.r.resp = slv_res_o.r.resp | r_chan_mst_q[i].resp; | |
| slv_res_o.r.data[i*AxiMstPortDataWidth+:AxiMstPortDataWidth] = r_chan_mst_q[i].data; | |
| end | |
| slv_res_o.r.data[(DownsizeFactor-1)*AxiMstPortDataWidth+:AxiMstPortDataWidth] = | |
| mst_res_i.r.data; | |
| end | |
| assign slv_res_o.r_valid = (&r_sel_q) ? mst_res_i.r_valid : 1'b0; | |
| assign mst_req_o.r_ready = (&r_sel_q) ? slv_req_i.r_ready : 1'b1; | |
| end else if (AxiMstPortDataWidth > AxiSlvPortDataWidth) begin : gen_upsizer | |
| localparam int unsigned UpsizeFactor = AxiMstPortDataWidth / AxiSlvPortDataWidth; | |
| localparam int unsigned SelOffset = $clog2(AxiSlvPortStrbWidth); | |
| localparam int unsigned SelWidth = $clog2(UpsizeFactor); | |
| typedef logic [SelWidth-1:0] sel_t; | |
| assign mst_req_o.aw = slv_req_i.aw; | |
| logic lock_aw_q, lock_aw_d, load_aw_lock; | |
| logic w_full, w_empty, w_push, w_pop; | |
| sel_t aw_sel, w_sel; | |
| always_comb begin : proc_aw_handshake | |
| load_aw_lock = 1'b0; | |
| mst_req_o.aw_valid = 1'b0; | |
| slv_res_o.aw_ready = 1'b0; | |
| w_push = 1'b0; | |
| if (lock_aw_q) begin | |
| mst_req_o.aw_valid = 1'b1; | |
| slv_res_o.aw_ready = mst_res_i.aw_ready; | |
| if (mst_res_i.aw_ready) begin | |
| load_aw_lock = 1'b1; | |
| end | |
| end else begin | |
| if (!w_full) begin | |
| mst_req_o.aw_valid = slv_req_i.aw_valid; | |
| slv_res_o.aw_ready = mst_res_i.aw_ready; | |
| if (slv_req_i.aw_valid) begin | |
| w_push = 1'b1; | |
| if (!mst_res_i.aw_ready) begin | |
| load_aw_lock = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| assign lock_aw_d = ~lock_aw_q; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| lock_aw_q <= (1'b0); | |
| end else begin | |
| if (load_aw_lock) begin | |
| lock_aw_q <= (lock_aw_d); | |
| end | |
| end | |
| end | |
| assign aw_sel = sel_t'(slv_req_i.aw.addr >> SelOffset); | |
| fifo_v3 #( | |
| .FALL_THROUGH ( 1'b1 ), | |
| .DEPTH ( UpsizeFactor ), | |
| .dtype ( sel_t ) | |
| ) i_fifo_w_sel ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .full_o ( w_full ), | |
| .empty_o ( w_empty ), | |
| .usage_o ( ), | |
| .data_i ( aw_sel ), | |
| .push_i ( w_push ), | |
| .data_o ( w_sel ), | |
| .pop_i ( w_pop ) | |
| ); | |
| assign w_pop = mst_req_o.w_valid & mst_res_i.w_ready; | |
| assign mst_req_o.w = axi_lite_mst_w_t'{ | |
| data: {UpsizeFactor{slv_req_i.w.data}}, | |
| strb: {AxiMstPortStrbWidth{1'b0}} | (slv_req_i.w.strb << (w_sel * AxiSlvPortStrbWidth)), | |
| default: '0 | |
| }; | |
| assign mst_req_o.w_valid = slv_req_i.w_valid & ~w_empty; | |
| assign slv_res_o.w_ready = mst_res_i.w_ready & ~w_empty; | |
| assign slv_res_o.b = mst_res_i.b; | |
| assign slv_res_o.b_valid = mst_res_i.b_valid; | |
| assign mst_req_o.b_ready = slv_req_i.b_ready; | |
| assign mst_req_o.ar = slv_req_i.ar; | |
| logic lock_ar_q, lock_ar_d, load_ar_lock; | |
| logic r_full, r_empty, r_push, r_pop; | |
| sel_t ar_sel, r_sel; | |
| always_comb begin : proc_ar_handshake | |
| load_ar_lock = 1'b0; | |
| mst_req_o.ar_valid = 1'b0; | |
| slv_res_o.ar_ready = 1'b0; | |
| r_push = 1'b0; | |
| if (lock_ar_q) begin | |
| mst_req_o.ar_valid = 1'b1; | |
| slv_res_o.ar_ready = mst_res_i.ar_ready; | |
| if (mst_res_i.ar_ready) begin | |
| load_ar_lock = 1'b1; | |
| end | |
| end else begin | |
| if (!r_full) begin | |
| mst_req_o.ar_valid = slv_req_i.ar_valid; | |
| slv_res_o.ar_ready = mst_res_i.ar_ready; | |
| if (slv_req_i.ar_valid) begin | |
| r_push = 1'b1; | |
| if (!mst_res_i.ar_ready) begin | |
| load_ar_lock = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| end | |
| assign lock_ar_d = ~lock_ar_q; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| lock_ar_q <= (1'b0); | |
| end else begin | |
| if (load_ar_lock) begin | |
| lock_ar_q <= (lock_ar_d); | |
| end | |
| end | |
| end | |
| assign ar_sel = sel_t'(slv_req_i.ar.addr >> SelOffset); | |
| fifo_v3 #( | |
| .FALL_THROUGH ( 1'b1 ), | |
| .DEPTH ( UpsizeFactor ), | |
| .dtype ( sel_t ) | |
| ) i_fifo_r_sel ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .full_o ( r_full ), | |
| .empty_o ( r_empty ), | |
| .usage_o ( ), | |
| .data_i ( ar_sel ), | |
| .push_i ( r_push ), | |
| .data_o ( r_sel ), | |
| .pop_i ( r_pop ) | |
| ); | |
| assign r_pop = slv_res_o.r_valid & slv_req_i.r_ready; | |
| assign slv_res_o.r = axi_lite_slv_r_t'{ | |
| data: mst_res_i.r.data[(r_sel*AxiSlvPortDataWidth)+:AxiSlvPortDataWidth], | |
| resp: mst_res_i.r.resp, | |
| default: '0 | |
| }; | |
| assign slv_res_o.r_valid = mst_res_i.r_valid & ~r_empty; | |
| assign mst_req_o.r_ready = slv_req_i.r_ready & ~r_empty; | |
| end else begin : gen_passthrough | |
| assign mst_req_o = slv_req_i; | |
| assign slv_res_o = mst_res_i; | |
| end | |
| endmodule | |
| module axi_lite_dw_converter_intf #( | |
| parameter int unsigned AXI_ADDR_WIDTH = 32'd0, | |
| parameter int unsigned AXI_SLV_PORT_DATA_WIDTH = 32'd0, | |
| parameter int unsigned AXI_MST_PORT_DATA_WIDTH = 32'd0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| AXI_LITE.Slave slv, | |
| AXI_LITE.Master mst | |
| ); | |
| localparam int unsigned AxiStrbWidthSlv = AXI_SLV_PORT_DATA_WIDTH / 32'd8; | |
| localparam int unsigned AxiStrbWidthMst = AXI_MST_PORT_DATA_WIDTH / 32'd8; | |
| typedef logic [AXI_ADDR_WIDTH-1:0] lite_addr_t; | |
| typedef logic [AXI_SLV_PORT_DATA_WIDTH-1:0] lite_data_slv_t; | |
| typedef logic [AxiStrbWidthSlv-1:0] lite_strb_slv_t; | |
| typedef logic [AXI_MST_PORT_DATA_WIDTH-1:0] lite_data_mst_t; | |
| typedef logic [AxiStrbWidthMst-1:0] lite_strb_mst_t; | |
| typedef struct packed { | |
| lite_addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_lite_t; | |
| typedef struct packed { | |
| lite_data_slv_t data; | |
| lite_strb_slv_t strb; | |
| } w_chan_lite_slv_t; | |
| typedef struct packed { | |
| lite_data_mst_t data; | |
| lite_strb_mst_t strb; | |
| } w_chan_lite_mst_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_lite_t; | |
| typedef struct packed { | |
| lite_addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_lite_t; | |
| typedef struct packed { | |
| lite_data_slv_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_lite_slv_t; | |
| typedef struct packed { | |
| lite_data_mst_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_lite_mst_t; | |
| typedef struct packed { | |
| aw_chan_lite_t aw; | |
| logic aw_valid; | |
| w_chan_lite_slv_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_lite_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } req_lite_slv_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_lite_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_lite_slv_t r; | |
| logic r_valid; | |
| } res_lite_slv_t; | |
| typedef struct packed { | |
| aw_chan_lite_t aw; | |
| logic aw_valid; | |
| w_chan_lite_mst_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_lite_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } req_lite_mst_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_lite_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_lite_mst_t r; | |
| logic r_valid; | |
| } res_lite_mst_t; | |
| req_lite_slv_t slv_req; | |
| res_lite_slv_t slv_res; | |
| req_lite_mst_t mst_req; | |
| res_lite_mst_t mst_res; | |
| assign slv_req.aw.addr = slv.aw_addr; | |
| assign slv_req.aw.prot = slv.aw_prot; | |
| assign slv_req.aw_valid = slv.aw_valid; | |
| assign slv_req.w.data = slv.w_data; | |
| assign slv_req.w.strb = slv.w_strb; | |
| assign slv_req.w_valid = slv.w_valid; | |
| assign slv_req.b_ready = slv.b_ready; | |
| assign slv_req.ar.addr = slv.ar_addr; | |
| assign slv_req.ar.prot = slv.ar_prot; | |
| assign slv_req.ar_valid = slv.ar_valid; | |
| assign slv_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = slv_res.aw_ready; | |
| assign slv.ar_ready = slv_res.ar_ready; | |
| assign slv.w_ready = slv_res.w_ready; | |
| assign slv.b_valid = slv_res.b_valid; | |
| assign slv.b_resp = slv_res.b.resp; | |
| assign slv.r_valid = slv_res.r_valid; | |
| assign slv.r_data = slv_res.r.data; | |
| assign slv.r_resp = slv_res.r.resp; | |
| assign mst.aw_addr = mst_req.aw.addr; | |
| assign mst.aw_prot = mst_req.aw.prot; | |
| assign mst.aw_valid = mst_req.aw_valid; | |
| assign mst.w_data = mst_req.w.data; | |
| assign mst.w_strb = mst_req.w.strb; | |
| assign mst.w_valid = mst_req.w_valid; | |
| assign mst.b_ready = mst_req.b_ready; | |
| assign mst.ar_addr = mst_req.ar.addr; | |
| assign mst.ar_prot = mst_req.ar.prot; | |
| assign mst.ar_valid = mst_req.ar_valid; | |
| assign mst.r_ready = mst_req.r_ready; | |
| assign mst_res.aw_ready = mst.aw_ready; | |
| assign mst_res.ar_ready = mst.ar_ready; | |
| assign mst_res.w_ready = mst.w_ready; | |
| assign mst_res.b_valid = mst.b_valid; | |
| assign mst_res.b.resp = mst.b_resp; | |
| assign mst_res.r_valid = mst.r_valid; | |
| assign mst_res.r.data = mst.r_data; | |
| assign mst_res.r.resp = mst.r_resp; | |
| axi_lite_dw_converter #( | |
| .AxiAddrWidth ( AXI_ADDR_WIDTH ), | |
| .AxiSlvPortDataWidth ( AXI_SLV_PORT_DATA_WIDTH ), | |
| .AxiMstPortDataWidth ( AXI_MST_PORT_DATA_WIDTH ), | |
| .axi_lite_aw_t ( aw_chan_lite_t ), | |
| .axi_lite_slv_w_t ( w_chan_lite_slv_t ), | |
| .axi_lite_mst_w_t ( w_chan_lite_mst_t ), | |
| .axi_lite_b_t ( b_chan_lite_t ), | |
| .axi_lite_ar_t ( ar_chan_lite_t ), | |
| .axi_lite_slv_r_t ( r_chan_lite_slv_t ), | |
| .axi_lite_mst_r_t ( r_chan_lite_mst_t ), | |
| .axi_lite_slv_req_t ( req_lite_slv_t ), | |
| .axi_lite_slv_res_t ( res_lite_slv_t ), | |
| .axi_lite_mst_req_t ( req_lite_mst_t ), | |
| .axi_lite_mst_res_t ( res_lite_mst_t ) | |
| ) i_axi_lite_dw_converter ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_req ), | |
| .slv_res_o ( slv_res ), | |
| .mst_req_o ( mst_req ), | |
| .mst_res_i ( mst_res ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_from_mem #( | |
| parameter int unsigned MemAddrWidth = 32'd0, | |
| parameter int unsigned AxiAddrWidth = 32'd0, | |
| parameter int unsigned DataWidth = 32'd0, | |
| parameter int unsigned MaxRequests = 32'd0, | |
| parameter axi_pkg::prot_t AxiProt = 3'b000, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_rsp_t = logic, | |
| parameter type mem_addr_t = logic[MemAddrWidth-1:0], | |
| parameter type axi_addr_t = logic[AxiAddrWidth-1:0], | |
| parameter type data_t = logic[DataWidth-1:0], | |
| parameter type strb_t = logic[DataWidth/8-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic mem_req_i, | |
| input mem_addr_t mem_addr_i, | |
| input logic mem_we_i, | |
| input data_t mem_wdata_i, | |
| input strb_t mem_be_i, | |
| output logic mem_gnt_o, | |
| output logic mem_rsp_valid_o, | |
| output data_t mem_rsp_rdata_o, | |
| output logic mem_rsp_error_o, | |
| output axi_req_t axi_req_o, | |
| input axi_rsp_t axi_rsp_i | |
| ); | |
| logic fifo_full, fifo_empty; | |
| logic aw_sent_q, aw_sent_d; | |
| logic w_sent_q, w_sent_d; | |
| always_comb begin | |
| axi_req_o.aw = '0; | |
| axi_req_o.aw.addr = axi_addr_t'(mem_addr_i); | |
| axi_req_o.aw.prot = AxiProt; | |
| axi_req_o.aw_valid = 1'b0; | |
| axi_req_o.w = '0; | |
| axi_req_o.w.data = mem_wdata_i; | |
| axi_req_o.w.strb = mem_be_i; | |
| axi_req_o.w_valid = 1'b0; | |
| axi_req_o.ar = '0; | |
| axi_req_o.ar.addr = axi_addr_t'(mem_addr_i); | |
| axi_req_o.ar.prot = AxiProt; | |
| axi_req_o.ar_valid = 1'b0; | |
| mem_gnt_o = 1'b0; | |
| aw_sent_d = aw_sent_q; | |
| w_sent_d = w_sent_q; | |
| if (mem_req_i && !fifo_full) begin | |
| if (!mem_we_i) begin | |
| axi_req_o.ar_valid = 1'b1; | |
| mem_gnt_o = axi_rsp_i.ar_ready; | |
| end else begin | |
| unique case ({aw_sent_q, w_sent_q}) | |
| 2'b00 : begin | |
| axi_req_o.aw_valid = 1'b1; | |
| axi_req_o.w_valid = 1'b1; | |
| unique case ({axi_rsp_i.aw_ready, axi_rsp_i.w_ready}) | |
| 2'b01 : begin | |
| w_sent_d = 1'b1; | |
| end | |
| 2'b10 : begin | |
| aw_sent_d = 1'b1; | |
| end | |
| 2'b11 : begin | |
| mem_gnt_o = 1'b1; | |
| end | |
| default : ; | |
| endcase | |
| end | |
| 2'b10 : begin | |
| axi_req_o.w_valid = 1'b1; | |
| if (axi_rsp_i.w_ready) begin | |
| aw_sent_d = 1'b0; | |
| mem_gnt_o = 1'b1; | |
| end | |
| end | |
| 2'b01 : begin | |
| axi_req_o.aw_valid = 1'b1; | |
| if (axi_rsp_i.aw_ready) begin | |
| w_sent_d = 1'b0; | |
| mem_gnt_o = 1'b1; | |
| end | |
| end | |
| default : begin | |
| aw_sent_d = 1'b0; | |
| w_sent_d = 1'b0; | |
| end | |
| endcase | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| aw_sent_q <= (1'b0); | |
| end else begin | |
| aw_sent_q <= (aw_sent_d); | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| w_sent_q <= (1'b0); | |
| end else begin | |
| w_sent_q <= (w_sent_d); | |
| end | |
| end | |
| logic rsp_sel; | |
| fifo_v3 #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DEPTH ( MaxRequests ), | |
| .dtype ( logic ) | |
| ) i_fifo_rsp_mux ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .full_o ( fifo_full ), | |
| .empty_o ( fifo_empty ), | |
| .usage_o ( ), | |
| .data_i ( mem_we_i ), | |
| .push_i ( mem_gnt_o ), | |
| .data_o ( rsp_sel ), | |
| .pop_i ( mem_rsp_valid_o ) | |
| ); | |
| assign axi_req_o.b_ready = !fifo_empty && rsp_sel; | |
| assign axi_req_o.r_ready = !fifo_empty && !rsp_sel; | |
| assign mem_rsp_rdata_o = axi_rsp_i.r.data; | |
| assign mem_rsp_error_o = rsp_sel ? | |
| (axi_rsp_i.b.resp inside {axi_pkg::RESP_SLVERR, axi_pkg::RESP_DECERR}) : | |
| (axi_rsp_i.r.resp inside {axi_pkg::RESP_SLVERR, axi_pkg::RESP_DECERR}); | |
| assign mem_rsp_valid_o = (axi_rsp_i.b_valid && axi_req_o.b_ready) || | |
| (axi_rsp_i.r_valid && axi_req_o.r_ready); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_join_intf ( | |
| AXI_LITE.Slave in, | |
| AXI_LITE.Master out | |
| ); | |
| assign out.aw_addr = in.aw_addr; | |
| assign out.aw_prot = in.aw_prot; | |
| assign out.aw_valid = in.aw_valid; | |
| assign in.aw_ready = out.aw_ready; | |
| assign out.w_data = in.w_data; | |
| assign out.w_strb = in.w_strb; | |
| assign out.w_valid = in.w_valid; | |
| assign in.w_ready = out.w_ready; | |
| assign in.b_resp = out.b_resp; | |
| assign in.b_valid = out.b_valid; | |
| assign out.b_ready = in.b_ready; | |
| assign out.ar_addr = in.ar_addr; | |
| assign out.ar_prot = in.ar_prot; | |
| assign out.ar_valid = in.ar_valid; | |
| assign in.ar_ready = out.ar_ready; | |
| assign in.r_data = out.r_data; | |
| assign in.r_resp = out.r_resp; | |
| assign in.r_valid = out.r_valid; | |
| assign out.r_ready = in.r_ready; | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_lfsr #( | |
| parameter int unsigned DataWidth = 32'd0, | |
| parameter type axi_lite_req_t = logic, | |
| parameter type axi_lite_rsp_t = logic | |
| )( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic testmode_i, | |
| input axi_lite_req_t req_i, | |
| output axi_lite_rsp_t rsp_o, | |
| input logic w_ser_data_i, | |
| output logic w_ser_data_o, | |
| input logic w_ser_en_i, | |
| input logic r_ser_data_i, | |
| output logic r_ser_data_o, | |
| input logic r_ser_en_i | |
| ); | |
| localparam int unsigned StrbWidth = DataWidth / 8; | |
| logic w_lfsr_en; | |
| logic r_lfsr_en; | |
| logic w_b_fifo_ready; | |
| logic w_b_fifo_valid; | |
| logic [DataWidth-1:0] w_data_in, w_data_out; | |
| assign rsp_o.aw_ready = !w_ser_en_i; | |
| axi_opt_lfsr #( | |
| .Width ( DataWidth ) | |
| ) i_axi_opt_lfsr_w ( | |
| .clk_i, | |
| .rst_ni, | |
| .en_i ( w_lfsr_en ), | |
| .ser_data_i ( w_ser_data_i ), | |
| .ser_data_o ( w_ser_data_o ), | |
| .ser_en_i ( w_ser_en_i ), | |
| .inp_en_i ( w_lfsr_en ), | |
| .data_i ( w_data_in ), | |
| .data_o ( w_data_out ) | |
| ); | |
| assign w_lfsr_en = req_i.w_valid & rsp_o.w_ready; | |
| assign rsp_o.w_ready = !w_ser_en_i & w_b_fifo_ready; | |
| always_comb begin : gen_data_strb_connect | |
| for (int unsigned i = 0; i < StrbWidth; i++) begin : gen_strb_en | |
| if (req_i.w.strb[i] == 1'b0) begin | |
| w_data_in[i*8+:8] = w_data_out[i*8+:8]; | |
| end else if (req_i.w.strb[i] == 1'b1) begin | |
| w_data_in[i*8+:8] = req_i.w.data[i*8+:8]; | |
| end else begin | |
| w_data_in[i*8+:8] = 'x; | |
| end | |
| end | |
| end | |
| stream_fifo #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DATA_WIDTH ( 'd1 ), | |
| .DEPTH ( 'd2 ) | |
| ) i_stream_fifo_w_b ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i, | |
| .flush_i ( 1'b0 ), | |
| .usage_o ( ), | |
| .data_i ( 1'b0 ), | |
| .valid_i ( req_i.w_valid ), | |
| .ready_o ( w_b_fifo_ready ), | |
| .data_o ( ), | |
| .valid_o ( w_b_fifo_valid ), | |
| .ready_i ( req_i.b_ready ) | |
| ); | |
| assign rsp_o.b.resp = axi_pkg::RESP_OKAY; | |
| assign rsp_o.b_valid = w_b_fifo_valid; | |
| assign rsp_o.ar_ready = !w_ser_en_i; | |
| axi_opt_lfsr #( | |
| .Width ( DataWidth ) | |
| ) i_axi_opt_lfsr_r ( | |
| .clk_i, | |
| .rst_ni, | |
| .en_i ( r_lfsr_en ), | |
| .ser_data_i ( r_ser_data_i ), | |
| .ser_data_o ( r_ser_data_o ), | |
| .ser_en_i ( r_ser_en_i ), | |
| .inp_en_i ( 1'b0 ), | |
| .data_i ( ), | |
| .data_o ( rsp_o.r.data ) | |
| ); | |
| assign rsp_o.r.resp = axi_pkg::RESP_OKAY; | |
| assign r_lfsr_en = req_i.r_ready & rsp_o.r_valid; | |
| assign rsp_o.r_valid = !r_ser_en_i; | |
| endmodule : axi_lite_lfsr | |
| module axi_opt_lfsr #( | |
| parameter int unsigned Width = 32'd0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic en_i, | |
| input logic ser_data_i, | |
| output logic ser_data_o, | |
| input logic ser_en_i, | |
| input logic inp_en_i, | |
| input logic [Width-1:0] data_i, | |
| output logic [Width-1:0] data_o | |
| ); | |
| localparam int unsigned LfsrIdxWidth = cf_math_pkg::idx_width(Width); | |
| localparam int unsigned MaxNumTabs = 4; | |
| typedef logic [LfsrIdxWidth:0] xnor_entry_t [MaxNumTabs-1:0]; | |
| xnor_entry_t XnorFeedback; | |
| logic [Width-1:0] reg_d, reg_q; | |
| logic xnor_feedback; | |
| always_comb begin : gen_register | |
| xnor_feedback = reg_q[XnorFeedback[MaxNumTabs-1]-1]; | |
| case (Width) | |
| 'd8 : XnorFeedback = { 'd8, 'd6, 'd5, 'd4 }; | |
| 'd16 : XnorFeedback = { 'd16, 'd14, 'd13, 'd11 }; | |
| 'd32 : XnorFeedback = { 'd32, 'd30, 'd26, 'd25 }; | |
| 'd64 : XnorFeedback = { 'd64, 'd63, 'd61, 'd60 }; | |
| 'd128 : XnorFeedback = { 'd128, 'd127, 'd126, 'd119 }; | |
| 'd256 : XnorFeedback = { 'd256, 'd256, 'd521, 'd246 }; | |
| 'd512 : XnorFeedback = { 'd512, 'd510, 'd507, 'd504 }; | |
| 'd1024 : XnorFeedback = { 'd1024, 'd1015, 'd1002, 'd1001 }; | |
| default : XnorFeedback = { 'x, 'x, 'x, 'x }; | |
| endcase | |
| if (inp_en_i) begin | |
| for (int unsigned i = 0; i < Width - 1; i++) begin : gen_comp_conection | |
| reg_d[i] = reg_q[i+1] ^ data_i[i]; | |
| end | |
| end else begin | |
| for (int unsigned i = 0; i < Width - 1; i++) begin : gen_gen_conection | |
| reg_d[i] = reg_q[i+1]; | |
| end | |
| end | |
| if (ser_en_i) begin | |
| reg_d[Width-1] = ser_data_i; | |
| end else begin | |
| for (int unsigned t = 0; t < MaxNumTabs - 1; t++) begin : gen_feedback_path | |
| xnor_feedback = xnor_feedback; | |
| if (XnorFeedback[t] != 0) begin | |
| xnor_feedback = xnor_feedback ^ reg_q[XnorFeedback[t]-1]; | |
| end | |
| end | |
| reg_d[Width-1] = inp_en_i ? xnor_feedback ^ data_i[Width-1] : xnor_feedback; | |
| end | |
| end | |
| assign ser_data_o = reg_q[0]; | |
| assign data_o = reg_q; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| reg_q <= ('1); | |
| end else begin | |
| if (en_i | ser_en_i) begin | |
| reg_q <= (reg_d); | |
| end | |
| end | |
| end | |
| endmodule : axi_opt_lfsr | |
| `begin_keywords "1800-2023" | |
| module axi_lite_mailbox #( | |
| parameter int unsigned MailboxDepth = 32'd0, | |
| parameter bit unsigned IrqEdgeTrig = 1'b0, | |
| parameter bit unsigned IrqActHigh = 1'b1, | |
| parameter int unsigned AxiAddrWidth = 32'd0, | |
| parameter int unsigned AxiDataWidth = 32'd0, | |
| parameter type req_lite_t = logic, | |
| parameter type resp_lite_t = logic, | |
| parameter type addr_t = logic [AxiAddrWidth-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| input req_lite_t [1:0] slv_reqs_i, | |
| output resp_lite_t [1:0] slv_resps_o, | |
| output logic [1:0] irq_o, | |
| input addr_t [1:0] base_addr_i | |
| ); | |
| localparam int unsigned FifoUsageWidth = $clog2(MailboxDepth); | |
| typedef logic [AxiDataWidth-1:0] data_t; | |
| typedef logic [FifoUsageWidth:0] usage_t; | |
| logic [1:0] mbox_full, mbox_empty; | |
| logic [1:0] mbox_push, mbox_pop; | |
| logic [1:0] w_mbox_flush, r_mbox_flush; | |
| data_t [1:0] mbox_w_data, mbox_r_data; | |
| usage_t [1:0] mbox_usage; | |
| logic [1:0] slv_irq; | |
| logic [1:0] clear_irq; | |
| axi_lite_mailbox_slave #( | |
| .MailboxDepth ( MailboxDepth ), | |
| .AxiAddrWidth ( AxiAddrWidth ), | |
| .AxiDataWidth ( AxiDataWidth ), | |
| .req_lite_t ( req_lite_t ), | |
| .resp_lite_t ( resp_lite_t ), | |
| .addr_t ( addr_t ), | |
| .data_t ( data_t ), | |
| .usage_t ( usage_t ) | |
| ) i_slv_port_0 ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_reqs_i[0] ), | |
| .slv_resp_o ( slv_resps_o[0] ), | |
| .base_addr_i ( base_addr_i[0] ), | |
| .mbox_w_data_o ( mbox_w_data[0] ), | |
| .mbox_w_full_i ( mbox_full[0] ), | |
| .mbox_w_push_o ( mbox_push[0] ), | |
| .mbox_w_flush_o ( w_mbox_flush[0] ), | |
| .mbox_w_usage_i ( mbox_usage[0] ), | |
| .mbox_r_data_i ( mbox_r_data[0] ), | |
| .mbox_r_empty_i ( mbox_empty[1] ), | |
| .mbox_r_pop_o ( mbox_pop[0] ), | |
| .mbox_r_flush_o ( r_mbox_flush[0] ), | |
| .mbox_r_usage_i ( mbox_usage[1] ), | |
| .irq_o ( slv_irq[0] ), | |
| .clear_irq_o ( clear_irq[0] ) | |
| ); | |
| axi_lite_mailbox_slave #( | |
| .MailboxDepth ( MailboxDepth ), | |
| .AxiAddrWidth ( AxiAddrWidth ), | |
| .AxiDataWidth ( AxiDataWidth ), | |
| .req_lite_t ( req_lite_t ), | |
| .resp_lite_t ( resp_lite_t ), | |
| .addr_t ( addr_t ), | |
| .data_t ( data_t ), | |
| .usage_t ( usage_t ) | |
| ) i_slv_port_1 ( | |
| .clk_i, | |
| .rst_ni, | |
| .slv_req_i ( slv_reqs_i[1] ), | |
| .slv_resp_o ( slv_resps_o[1] ), | |
| .base_addr_i ( base_addr_i[1] ), | |
| .mbox_w_data_o ( mbox_w_data[1] ), | |
| .mbox_w_full_i ( mbox_full[1] ), | |
| .mbox_w_push_o ( mbox_push[1] ), | |
| .mbox_w_flush_o ( w_mbox_flush[1] ), | |
| .mbox_w_usage_i ( mbox_usage[1] ), | |
| .mbox_r_data_i ( mbox_r_data[1] ), | |
| .mbox_r_empty_i ( mbox_empty[0] ), | |
| .mbox_r_pop_o ( mbox_pop[1] ), | |
| .mbox_r_flush_o ( r_mbox_flush[1] ), | |
| .mbox_r_usage_i ( mbox_usage[0] ), | |
| .irq_o ( slv_irq[1] ), | |
| .clear_irq_o ( clear_irq[1] ) | |
| ); | |
| logic [FifoUsageWidth-1:0] mbox_0_to_1_usage, mbox_1_to_0_usage; | |
| fifo_v3 #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DEPTH ( MailboxDepth ), | |
| .dtype ( data_t ) | |
| ) i_mbox_0_to_1 ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i( test_i ), | |
| .flush_i ( w_mbox_flush[0] | r_mbox_flush[1] ), | |
| .full_o ( mbox_full[0] ), | |
| .empty_o ( mbox_empty[0] ), | |
| .usage_o ( mbox_0_to_1_usage ), | |
| .data_i ( mbox_w_data[0] ), | |
| .push_i ( mbox_push[0] ), | |
| .data_o ( mbox_r_data[1] ), | |
| .pop_i ( mbox_pop[1] ) | |
| ); | |
| assign mbox_usage[0] = {mbox_full[0], mbox_0_to_1_usage}; | |
| fifo_v3 #( | |
| .FALL_THROUGH ( 1'b0 ), | |
| .DEPTH ( MailboxDepth ), | |
| .dtype ( data_t ) | |
| ) i_mbox_1_to_0 ( | |
| .clk_i, | |
| .rst_ni, | |
| .testmode_i( test_i ), | |
| .flush_i ( w_mbox_flush[1] | r_mbox_flush[0] ), | |
| .full_o ( mbox_full[1] ), | |
| .empty_o ( mbox_empty[1] ), | |
| .usage_o ( mbox_1_to_0_usage ), | |
| .data_i ( mbox_w_data[1] ), | |
| .push_i ( mbox_push[1] ), | |
| .data_o ( mbox_r_data[0] ), | |
| .pop_i ( mbox_pop[0] ) | |
| ); | |
| assign mbox_usage[1] = {mbox_full[1], mbox_1_to_0_usage}; | |
| for (genvar i = 0; i < 2; i++) begin : gen_irq_conversion | |
| if (IrqEdgeTrig) begin : gen_irq_edge | |
| logic irq_q, irq_d, update_irq; | |
| always_comb begin | |
| irq_d = irq_q; | |
| update_irq = 1'b0; | |
| irq_o[i] = ~IrqActHigh; | |
| if (clear_irq[i]) begin | |
| irq_d = 1'b0; | |
| update_irq = 1'b1; | |
| end else if (!irq_q && slv_irq[i]) begin | |
| irq_d = 1'b1; | |
| update_irq = 1'b1; | |
| irq_o[i] = IrqActHigh; | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| irq_q <= ('0); | |
| end else begin | |
| if (update_irq) begin | |
| irq_q <= (irq_d); | |
| end | |
| end | |
| end | |
| end else begin : gen_irq_level | |
| assign irq_o[i] = (IrqActHigh) ? slv_irq[i] : ~slv_irq[i]; | |
| end | |
| end | |
| endmodule | |
| module axi_lite_mailbox_slave #( | |
| parameter int unsigned MailboxDepth = 32'd16, | |
| parameter int unsigned AxiAddrWidth = 32'd32, | |
| parameter int unsigned AxiDataWidth = 32'd32, | |
| parameter type req_lite_t = logic, | |
| parameter type resp_lite_t = logic, | |
| parameter type addr_t = logic [AxiAddrWidth-1:0], | |
| parameter type data_t = logic [AxiDataWidth-1:0], | |
| parameter type usage_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input req_lite_t slv_req_i, | |
| output resp_lite_t slv_resp_o, | |
| input addr_t base_addr_i, | |
| output data_t mbox_w_data_o, | |
| input logic mbox_w_full_i, | |
| output logic mbox_w_push_o, | |
| output logic mbox_w_flush_o, | |
| input usage_t mbox_w_usage_i, | |
| input data_t mbox_r_data_i, | |
| input logic mbox_r_empty_i, | |
| output logic mbox_r_pop_o, | |
| output logic mbox_r_flush_o, | |
| input usage_t mbox_r_usage_i, | |
| output logic irq_o, | |
| output logic clear_irq_o | |
| ); | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_lite_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_lite_t; | |
| localparam int unsigned NoRegs = 32'd10; | |
| typedef enum logic [3:0] { | |
| MBOXW = 4'd0, | |
| MBOXR = 4'd1, | |
| STATUS = 4'd2, | |
| ERROR = 4'd3, | |
| WIRQT = 4'd4, | |
| RIRQT = 4'd5, | |
| IRQS = 4'd6, | |
| IRQEN = 4'd7, | |
| IRQP = 4'd8, | |
| CTRL = 4'd9 | |
| } reg_e; | |
| typedef struct packed { | |
| int unsigned idx; | |
| addr_t start_addr; | |
| addr_t end_addr; | |
| } rule_t; | |
| typedef logic [$clog2(NoRegs)-1:0] idx_t; | |
| logic b_valid, b_ready; | |
| b_chan_lite_t b_chan; | |
| logic r_valid, r_ready; | |
| r_chan_lite_t r_chan; | |
| rule_t [NoRegs-1:0] addr_map; | |
| for (genvar i = 0; i < NoRegs; i++) begin : gen_addr_map | |
| assign addr_map[i] = '{ | |
| idx: i, | |
| start_addr: base_addr_i + i * (AxiDataWidth / 8), | |
| end_addr: base_addr_i + (i + 1) * (AxiDataWidth / 8), | |
| default: '0 | |
| }; | |
| end | |
| idx_t w_reg_idx, r_reg_idx; | |
| logic dec_w_valid, dec_r_valid; | |
| logic [3:0] status_q; | |
| logic [1:0] error_q, error_d; | |
| data_t wirqt_q, wirqt_d; | |
| data_t rirqt_q, rirqt_d; | |
| logic [2:0] irqs_q, irqs_d; | |
| logic [2:0] irqen_q, irqen_d; | |
| logic [2:0] irqp_q; | |
| logic [1:0] ctrl_q; | |
| logic update_regs; | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| error_q <= ('0); | |
| end else begin | |
| if (update_regs) begin | |
| error_q <= (error_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| wirqt_q <= ('0); | |
| end else begin | |
| if (update_regs) begin | |
| wirqt_q <= (wirqt_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| rirqt_q <= ('0); | |
| end else begin | |
| if (update_regs) begin | |
| rirqt_q <= (rirqt_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| irqs_q <= ('0); | |
| end else begin | |
| if (update_regs) begin | |
| irqs_q <= (irqs_d); | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| irqen_q <= ('0); | |
| end else begin | |
| if (update_regs) begin | |
| irqen_q <= (irqen_d); | |
| end | |
| end | |
| end | |
| for (genvar i = 0; i < (AxiDataWidth/8); i++) begin : gen_w_mbox_data | |
| assign mbox_w_data_o[i*8+:8] = slv_req_i.w.strb[i] ? slv_req_i.w.data[i*8+:8] : '0; | |
| end | |
| assign status_q = { mbox_r_usage_i > usage_t'(rirqt_q), | |
| mbox_w_usage_i > usage_t'(wirqt_q), | |
| mbox_w_full_i, | |
| mbox_r_empty_i }; | |
| assign irqp_q = irqs_q & irqen_q; | |
| assign ctrl_q = {mbox_r_flush_o, mbox_w_flush_o}; | |
| assign irq_o = |irqp_q; | |
| always_comb begin | |
| slv_resp_o.aw_ready = 1'b0; | |
| slv_resp_o.w_ready = 1'b0; | |
| b_chan = '{resp: axi_pkg::RESP_SLVERR}; | |
| b_valid = 1'b0; | |
| slv_resp_o.ar_ready = 1'b0; | |
| r_chan = '{data: '0, resp: axi_pkg::RESP_SLVERR}; | |
| r_valid = 1'b0; | |
| error_d = error_q; | |
| wirqt_d = wirqt_q; | |
| rirqt_d = rirqt_q; | |
| irqs_d = irqs_q; | |
| irqen_d = irqen_q; | |
| update_regs = 1'b0; | |
| mbox_w_push_o = 1'b0; | |
| mbox_w_flush_o = 1'b0; | |
| mbox_r_pop_o = 1'b0; | |
| mbox_r_flush_o = 1'b0; | |
| clear_irq_o = 1'b0; | |
| if (!irqs_q[1] && status_q[3]) begin | |
| irqs_d[1] = 1'b1; | |
| update_regs = 1'b1; | |
| end | |
| if (!irqs_q[0] && status_q[2]) begin | |
| irqs_d[0] = 1'b1; | |
| update_regs = 1'b1; | |
| end | |
| if (slv_req_i.ar_valid) begin | |
| if (dec_r_valid) begin | |
| unique case (reg_e'(r_reg_idx)) | |
| MBOXW: r_chan = '{data: data_t'( 32'hFEEDC0DE ), resp: axi_pkg::RESP_OKAY}; | |
| MBOXR: begin | |
| if (!mbox_r_empty_i) begin | |
| r_chan = '{data: data_t'( mbox_r_data_i ), resp: axi_pkg::RESP_OKAY}; | |
| mbox_r_pop_o = 1'b1; | |
| end else begin | |
| r_chan = '{data: data_t'( 32'hFEEDDEAD ), resp: axi_pkg::RESP_SLVERR}; | |
| error_d[0] = 1'b1; | |
| irqs_d[2] = 1'b1; | |
| update_regs = 1'b1; | |
| end | |
| end | |
| STATUS: r_chan = '{data: data_t'( status_q ), resp: axi_pkg::RESP_OKAY}; | |
| ERROR: begin | |
| r_chan = '{data: data_t'( error_q ), resp: axi_pkg::RESP_OKAY}; | |
| error_d = '0; | |
| update_regs = 1'b1; | |
| end | |
| WIRQT: r_chan = '{data: data_t'( wirqt_q ), resp: axi_pkg::RESP_OKAY}; | |
| RIRQT: r_chan = '{data: data_t'( rirqt_q ), resp: axi_pkg::RESP_OKAY}; | |
| IRQS: r_chan = '{data: data_t'( irqs_q ), resp: axi_pkg::RESP_OKAY}; | |
| IRQEN: r_chan = '{data: data_t'( irqen_q ), resp: axi_pkg::RESP_OKAY}; | |
| IRQP: r_chan = '{data: data_t'( irqp_q ), resp: axi_pkg::RESP_OKAY}; | |
| CTRL: r_chan = '{data: data_t'( ctrl_q ), resp: axi_pkg::RESP_OKAY}; | |
| default: ; | |
| endcase | |
| end | |
| r_valid = 1'b1; | |
| if (r_ready) begin | |
| slv_resp_o.ar_ready = 1'b1; | |
| end | |
| end | |
| if (slv_req_i.aw_valid && slv_req_i.w_valid) begin | |
| b_valid = 1'b1; | |
| if (b_ready) begin | |
| if (dec_w_valid) begin | |
| unique case (reg_e'(w_reg_idx)) | |
| MBOXW: begin | |
| if (!mbox_w_full_i) begin | |
| mbox_w_push_o = 1'b1; | |
| b_chan = '{resp: axi_pkg::RESP_OKAY}; | |
| end else begin | |
| error_d[1] = 1'b1; | |
| irqs_d[2] = 1'b1; | |
| update_regs = 1'b1; | |
| end | |
| end | |
| WIRQT: begin | |
| for (int unsigned i = 0; i < AxiDataWidth/8; i++) begin | |
| wirqt_d[i*8+:8] = slv_req_i.w.strb[i] ? slv_req_i.w.data[i*8+:8] : wirqt_d[i*8+:8]; | |
| end | |
| if (wirqt_d >= data_t'(MailboxDepth)) begin | |
| wirqt_d = data_t'(MailboxDepth) - data_t'(32'd1); | |
| end | |
| update_regs = 1'b1; | |
| b_chan = '{resp: axi_pkg::RESP_OKAY}; | |
| end | |
| RIRQT: begin | |
| for (int unsigned i = 0; i < AxiDataWidth/8; i++) begin | |
| rirqt_d[i*8+:8] = slv_req_i.w.strb[i] ? slv_req_i.w.data[i*8+:8] : rirqt_d[i*8+:8]; | |
| end | |
| if (rirqt_d >= data_t'(MailboxDepth)) begin | |
| rirqt_d = data_t'(MailboxDepth) - data_t'(32'd1); | |
| end | |
| update_regs = 1'b1; | |
| b_chan = '{resp: axi_pkg::RESP_OKAY}; | |
| end | |
| IRQS: begin | |
| if (slv_req_i.w.strb[0]) begin | |
| irqs_d[2] = slv_req_i.w.data[2] ? 1'b0 : irqs_d[2]; | |
| irqs_d[1] = slv_req_i.w.data[1] ? 1'b0 : irqs_d[1]; | |
| irqs_d[0] = slv_req_i.w.data[0] ? 1'b0 : irqs_d[0]; | |
| clear_irq_o = 1'b1; | |
| update_regs = 1'b1; | |
| end | |
| b_chan = '{resp: axi_pkg::RESP_OKAY}; | |
| end | |
| IRQEN: begin | |
| if (slv_req_i.w.strb[0]) begin | |
| irqen_d[2:0] = slv_req_i.w.data[2:0]; | |
| update_regs = 1'b1; | |
| end | |
| b_chan = '{resp: axi_pkg::RESP_OKAY}; | |
| end | |
| CTRL: begin | |
| if (slv_req_i.w.strb[0]) begin | |
| mbox_r_flush_o = slv_req_i.w.data[1]; | |
| mbox_w_flush_o = slv_req_i.w.data[0]; | |
| end | |
| b_chan = '{resp: axi_pkg::RESP_OKAY}; | |
| end | |
| default : ; | |
| endcase | |
| end | |
| slv_resp_o.aw_ready = 1'b1; | |
| slv_resp_o.w_ready = 1'b1; | |
| end | |
| end | |
| end | |
| addr_decode #( | |
| .NoIndices( NoRegs ), | |
| .NoRules ( NoRegs ), | |
| .addr_t ( addr_t ), | |
| .rule_t ( rule_t ) | |
| ) i_waddr_decode ( | |
| .addr_i ( slv_req_i.aw.addr ), | |
| .addr_map_i ( addr_map ), | |
| .idx_o ( w_reg_idx ), | |
| .dec_valid_o ( dec_w_valid ), | |
| .dec_error_o ( ), | |
| .en_default_idx_i ( 1'b0 ), | |
| .default_idx_i ( '0 ) | |
| ); | |
| spill_register #( | |
| .T ( b_chan_lite_t ) | |
| ) i_b_chan_outp ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( b_valid ), | |
| .ready_o ( b_ready ), | |
| .data_i ( b_chan ), | |
| .valid_o ( slv_resp_o.b_valid ), | |
| .ready_i ( slv_req_i.b_ready ), | |
| .data_o ( slv_resp_o.b ) | |
| ); | |
| addr_decode #( | |
| .NoIndices( NoRegs ), | |
| .NoRules ( NoRegs ), | |
| .addr_t ( addr_t ), | |
| .rule_t ( rule_t ) | |
| ) i_raddr_decode ( | |
| .addr_i ( slv_req_i.ar.addr ), | |
| .addr_map_i ( addr_map ), | |
| .idx_o ( r_reg_idx ), | |
| .dec_valid_o ( dec_r_valid ), | |
| .dec_error_o ( ), | |
| .en_default_idx_i ( 1'b0 ), | |
| .default_idx_i ( '0 ) | |
| ); | |
| spill_register #( | |
| .T ( r_chan_lite_t ) | |
| ) i_r_chan_outp ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( r_valid ), | |
| .ready_o ( r_ready ), | |
| .data_i ( r_chan ), | |
| .valid_o ( slv_resp_o.r_valid ), | |
| .ready_i ( slv_req_i.r_ready ), | |
| .data_o ( slv_resp_o.r ) | |
| ); | |
| endmodule | |
| module axi_lite_mailbox_intf #( | |
| parameter int unsigned MAILBOX_DEPTH = 32'd0, | |
| parameter bit unsigned IRQ_EDGE_TRIG = 1'b0, | |
| parameter bit unsigned IRQ_ACT_HIGH = 1'b1, | |
| parameter int unsigned AXI_ADDR_WIDTH = 32'd0, | |
| parameter int unsigned AXI_DATA_WIDTH = 32'd0, | |
| parameter type addr_t = logic [AXI_ADDR_WIDTH-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| AXI_LITE.Slave slv [1:0], | |
| output logic [1:0] irq_o, | |
| input addr_t [1:0] base_addr_i | |
| ); | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_lite_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_lite_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_lite_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_lite_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_lite_t; | |
| typedef struct packed { | |
| aw_chan_lite_t aw; | |
| logic aw_valid; | |
| w_chan_lite_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_lite_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } req_lite_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_lite_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_lite_t r; | |
| logic r_valid; | |
| } resp_lite_t; | |
| req_lite_t [1:0] slv_reqs; | |
| resp_lite_t [1:0] slv_resps; | |
| for (genvar i = 0; i < 2; i++) begin : gen_port_assign | |
| assign slv_reqs[i].aw.addr = slv[i].aw_addr; | |
| assign slv_reqs[i].aw.prot = slv[i].aw_prot; | |
| assign slv_reqs[i].aw_valid = slv[i].aw_valid; | |
| assign slv_reqs[i].w.data = slv[i].w_data; | |
| assign slv_reqs[i].w.strb = slv[i].w_strb; | |
| assign slv_reqs[i].w_valid = slv[i].w_valid; | |
| assign slv_reqs[i].b_ready = slv[i].b_ready; | |
| assign slv_reqs[i].ar.addr = slv[i].ar_addr; | |
| assign slv_reqs[i].ar.prot = slv[i].ar_prot; | |
| assign slv_reqs[i].ar_valid = slv[i].ar_valid; | |
| assign slv_reqs[i].r_ready = slv[i].r_ready; | |
| assign slv[i].aw_ready = slv_resps[i].aw_ready; | |
| assign slv[i].ar_ready = slv_resps[i].ar_ready; | |
| assign slv[i].w_ready = slv_resps[i].w_ready; | |
| assign slv[i].b_valid = slv_resps[i].b_valid; | |
| assign slv[i].b_resp = slv_resps[i].b.resp; | |
| assign slv[i].r_valid = slv_resps[i].r_valid; | |
| assign slv[i].r_data = slv_resps[i].r.data; | |
| assign slv[i].r_resp = slv_resps[i].r.resp; | |
| end | |
| axi_lite_mailbox #( | |
| .MailboxDepth ( MAILBOX_DEPTH ), | |
| .IrqEdgeTrig ( IRQ_EDGE_TRIG ), | |
| .IrqActHigh ( IRQ_ACT_HIGH ), | |
| .AxiAddrWidth ( AXI_ADDR_WIDTH ), | |
| .AxiDataWidth ( AXI_DATA_WIDTH ), | |
| .req_lite_t ( req_lite_t ), | |
| .resp_lite_t ( resp_lite_t ) | |
| ) i_axi_lite_mailbox ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i, | |
| .slv_reqs_i ( slv_reqs ), | |
| .slv_resps_o ( slv_resps ), | |
| .irq_o, | |
| .base_addr_i | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_mux #( | |
| parameter type aw_chan_t = logic, | |
| parameter type w_chan_t = logic, | |
| parameter type b_chan_t = logic, | |
| parameter type ar_chan_t = logic, | |
| parameter type r_chan_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic, | |
| parameter int unsigned NoSlvPorts = 32'd0, | |
| parameter int unsigned MaxTrans = 32'd0, | |
| parameter bit FallThrough = 1'b0, | |
| parameter bit SpillAw = 1'b1, | |
| parameter bit SpillW = 1'b0, | |
| parameter bit SpillB = 1'b0, | |
| parameter bit SpillAr = 1'b1, | |
| parameter bit SpillR = 1'b0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| input axi_req_t [NoSlvPorts-1:0] slv_reqs_i, | |
| output axi_resp_t [NoSlvPorts-1:0] slv_resps_o, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| if (NoSlvPorts == 32'h1) begin : gen_no_mux | |
| spill_register #( | |
| .T ( aw_chan_t ), | |
| .Bypass ( ~SpillAw ) | |
| ) i_aw_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_reqs_i[0].aw_valid ), | |
| .ready_o ( slv_resps_o[0].aw_ready ), | |
| .data_i ( slv_reqs_i[0].aw ), | |
| .valid_o ( mst_req_o.aw_valid ), | |
| .ready_i ( mst_resp_i.aw_ready ), | |
| .data_o ( mst_req_o.aw ) | |
| ); | |
| spill_register #( | |
| .T ( w_chan_t ), | |
| .Bypass ( ~SpillW ) | |
| ) i_w_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_reqs_i[0].w_valid ), | |
| .ready_o ( slv_resps_o[0].w_ready ), | |
| .data_i ( slv_reqs_i[0].w ), | |
| .valid_o ( mst_req_o.w_valid ), | |
| .ready_i ( mst_resp_i.w_ready ), | |
| .data_o ( mst_req_o.w ) | |
| ); | |
| spill_register #( | |
| .T ( b_chan_t ), | |
| .Bypass ( ~SpillB ) | |
| ) i_b_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_resp_i.b_valid ), | |
| .ready_o ( mst_req_o.b_ready ), | |
| .data_i ( mst_resp_i.b ), | |
| .valid_o ( slv_resps_o[0].b_valid ), | |
| .ready_i ( slv_reqs_i[0].b_ready ), | |
| .data_o ( slv_resps_o[0].b ) | |
| ); | |
| spill_register #( | |
| .T ( ar_chan_t ), | |
| .Bypass ( ~SpillAr ) | |
| ) i_ar_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( slv_reqs_i[0].ar_valid ), | |
| .ready_o ( slv_resps_o[0].ar_ready ), | |
| .data_i ( slv_reqs_i[0].ar ), | |
| .valid_o ( mst_req_o.ar_valid ), | |
| .ready_i ( mst_resp_i.ar_ready ), | |
| .data_o ( mst_req_o.ar ) | |
| ); | |
| spill_register #( | |
| .T ( r_chan_t ), | |
| .Bypass ( ~SpillR ) | |
| ) i_r_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_resp_i.r_valid ), | |
| .ready_o ( mst_req_o.r_ready ), | |
| .data_i ( mst_resp_i.r ), | |
| .valid_o ( slv_resps_o[0].r_valid ), | |
| .ready_i ( slv_reqs_i[0].r_ready ), | |
| .data_o ( slv_resps_o[0].r ) | |
| ); | |
| end else begin : gen_mux | |
| localparam int unsigned CLog2NoSlvPorts = $clog2(NoSlvPorts); | |
| typedef logic [CLog2NoSlvPorts-1:0] select_t; | |
| aw_chan_t [NoSlvPorts-1:0] slv_aw_chans; | |
| logic [NoSlvPorts-1:0] slv_aw_valids, slv_aw_readies; | |
| select_t aw_select; | |
| aw_chan_t mst_aw_chan; | |
| logic mst_aw_valid, mst_aw_ready; | |
| logic aw_valid, aw_ready; | |
| logic lock_aw_valid_d, lock_aw_valid_q; | |
| logic load_aw_lock; | |
| logic w_fifo_full, w_fifo_empty; | |
| logic w_fifo_push, w_fifo_pop; | |
| select_t w_select; | |
| w_chan_t mst_w_chan; | |
| logic mst_w_valid, mst_w_ready; | |
| select_t b_select; | |
| logic b_fifo_full, b_fifo_empty; | |
| logic b_fifo_pop; | |
| b_chan_t mst_b_chan; | |
| logic mst_b_valid, mst_b_ready; | |
| ar_chan_t [NoSlvPorts-1:0] slv_ar_chans; | |
| logic [NoSlvPorts-1:0] slv_ar_valids, slv_ar_readies; | |
| select_t ar_select; | |
| ar_chan_t mst_ar_chan; | |
| logic mst_ar_valid, mst_ar_ready; | |
| logic ar_valid, ar_ready; | |
| select_t r_select; | |
| logic r_fifo_full, r_fifo_empty; | |
| logic r_fifo_push, r_fifo_pop; | |
| r_chan_t mst_r_chan; | |
| logic mst_r_valid, mst_r_ready; | |
| for (genvar i = 0; i < NoSlvPorts; i++) begin : gen_aw_arb_input | |
| assign slv_aw_chans[i] = slv_reqs_i[i].aw; | |
| assign slv_aw_valids[i] = slv_reqs_i[i].aw_valid; | |
| assign slv_resps_o[i].aw_ready = slv_aw_readies[i]; | |
| end | |
| rr_arb_tree #( | |
| .NumIn ( NoSlvPorts ), | |
| .DataType ( aw_chan_t ), | |
| .AxiVldRdy( 1'b1 ), | |
| .LockIn ( 1'b1 ) | |
| ) i_aw_arbiter ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i( 1'b0 ), | |
| .rr_i ( '0 ), | |
| .req_i ( slv_aw_valids ), | |
| .gnt_o ( slv_aw_readies ), | |
| .data_i ( slv_aw_chans ), | |
| .gnt_i ( aw_ready ), | |
| .req_o ( aw_valid ), | |
| .data_o ( mst_aw_chan ), | |
| .idx_o ( aw_select ) | |
| ); | |
| always_comb begin | |
| lock_aw_valid_d = lock_aw_valid_q; | |
| load_aw_lock = 1'b0; | |
| w_fifo_push = 1'b0; | |
| mst_aw_valid = 1'b0; | |
| aw_ready = 1'b0; | |
| if (lock_aw_valid_q) begin | |
| mst_aw_valid = 1'b1; | |
| if (mst_aw_ready) begin | |
| aw_ready = 1'b1; | |
| lock_aw_valid_d = 1'b0; | |
| load_aw_lock = 1'b1; | |
| end | |
| end else begin | |
| if (!w_fifo_full && aw_valid) begin | |
| mst_aw_valid = 1'b1; | |
| w_fifo_push = 1'b1; | |
| if (mst_aw_ready) begin | |
| aw_ready = 1'b1; | |
| end else begin | |
| lock_aw_valid_d = 1'b1; | |
| load_aw_lock = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| lock_aw_valid_q <= ('0); | |
| end else begin | |
| if (load_aw_lock) begin | |
| lock_aw_valid_q <= (lock_aw_valid_d); | |
| end | |
| end | |
| end | |
| fifo_v3 #( | |
| .FALL_THROUGH ( FallThrough ), | |
| .DEPTH ( MaxTrans ), | |
| .dtype ( select_t ) | |
| ) i_w_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i( test_i ), | |
| .full_o ( w_fifo_full ), | |
| .empty_o ( w_fifo_empty ), | |
| .usage_o ( ), | |
| .data_i ( aw_select ), | |
| .push_i ( w_fifo_push ), | |
| .data_o ( w_select ), | |
| .pop_i ( w_fifo_pop ) | |
| ); | |
| spill_register #( | |
| .T ( aw_chan_t ), | |
| .Bypass ( ~SpillAw ) | |
| ) i_aw_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_aw_valid ), | |
| .ready_o ( mst_aw_ready ), | |
| .data_i ( mst_aw_chan ), | |
| .valid_o ( mst_req_o.aw_valid ), | |
| .ready_i ( mst_resp_i.aw_ready ), | |
| .data_o ( mst_req_o.aw ) | |
| ); | |
| assign mst_w_chan = slv_reqs_i[w_select].w; | |
| assign mst_w_valid = (!w_fifo_empty && !b_fifo_full) ? slv_reqs_i[w_select].w_valid : 1'b0; | |
| for (genvar i = 0; i < NoSlvPorts; i++) begin : gen_slv_w_ready | |
| assign slv_resps_o[i].w_ready = mst_w_ready & ~w_fifo_empty & | |
| ~b_fifo_full & (w_select == select_t'(i)); | |
| end | |
| assign w_fifo_pop = mst_w_valid & mst_w_ready; | |
| fifo_v3 #( | |
| .FALL_THROUGH ( FallThrough ), | |
| .DEPTH ( MaxTrans ), | |
| .dtype ( select_t ) | |
| ) i_b_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i( test_i ), | |
| .full_o ( b_fifo_full ), | |
| .empty_o ( b_fifo_empty ), | |
| .usage_o ( ), | |
| .data_i ( w_select ), | |
| .push_i ( w_fifo_pop ), | |
| .data_o ( b_select ), | |
| .pop_i ( b_fifo_pop ) | |
| ); | |
| spill_register #( | |
| .T ( w_chan_t ), | |
| .Bypass ( ~SpillW ) | |
| ) i_w_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_w_valid ), | |
| .ready_o ( mst_w_ready ), | |
| .data_i ( mst_w_chan ), | |
| .valid_o ( mst_req_o.w_valid ), | |
| .ready_i ( mst_resp_i.w_ready ), | |
| .data_o ( mst_req_o.w ) | |
| ); | |
| for (genvar i = 0; i < NoSlvPorts; i++) begin : gen_slv_resps_b | |
| assign slv_resps_o[i].b = mst_b_chan; | |
| assign slv_resps_o[i].b_valid = mst_b_valid & ~b_fifo_empty & (b_select == select_t'(i)); | |
| end | |
| assign mst_b_ready = ~b_fifo_empty & slv_reqs_i[b_select].b_ready; | |
| assign b_fifo_pop = mst_b_valid & mst_b_ready; | |
| spill_register #( | |
| .T ( b_chan_t ), | |
| .Bypass ( ~SpillB ) | |
| ) i_b_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_resp_i.b_valid ), | |
| .ready_o ( mst_req_o.b_ready ), | |
| .data_i ( mst_resp_i.b ), | |
| .valid_o ( mst_b_valid ), | |
| .ready_i ( mst_b_ready ), | |
| .data_o ( mst_b_chan ) | |
| ); | |
| for (genvar i = 0; i < NoSlvPorts; i++) begin : gen_ar_arb_input | |
| assign slv_ar_chans[i] = slv_reqs_i[i].ar; | |
| assign slv_ar_valids[i] = slv_reqs_i[i].ar_valid; | |
| assign slv_resps_o[i].ar_ready = slv_ar_readies[i]; | |
| end | |
| rr_arb_tree #( | |
| .NumIn ( NoSlvPorts ), | |
| .DataType ( ar_chan_t ), | |
| .AxiVldRdy( 1'b1 ), | |
| .LockIn ( 1'b1 ) | |
| ) i_ar_arbiter ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i( 1'b0 ), | |
| .rr_i ( '0 ), | |
| .req_i ( slv_ar_valids ), | |
| .gnt_o ( slv_ar_readies ), | |
| .data_i ( slv_ar_chans ), | |
| .gnt_i ( ar_ready ), | |
| .req_o ( ar_valid ), | |
| .data_o ( mst_ar_chan ), | |
| .idx_o ( ar_select ) | |
| ); | |
| assign mst_ar_valid = (!r_fifo_full) ? ar_valid : 1'b0; | |
| assign ar_ready = (!r_fifo_full) ? mst_ar_ready : 1'b0; | |
| assign r_fifo_push = mst_ar_valid & mst_ar_ready; | |
| fifo_v3 #( | |
| .FALL_THROUGH ( FallThrough ), | |
| .DEPTH ( MaxTrans ), | |
| .dtype ( select_t ) | |
| ) i_r_fifo ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .flush_i ( 1'b0 ), | |
| .testmode_i( test_i ), | |
| .full_o ( r_fifo_full ), | |
| .empty_o ( r_fifo_empty ), | |
| .usage_o ( ), | |
| .data_i ( ar_select ), | |
| .push_i ( r_fifo_push ), | |
| .data_o ( r_select ), | |
| .pop_i ( r_fifo_pop ) | |
| ); | |
| spill_register #( | |
| .T ( ar_chan_t ), | |
| .Bypass ( ~SpillAr ) | |
| ) i_ar_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_ar_valid ), | |
| .ready_o ( mst_ar_ready ), | |
| .data_i ( mst_ar_chan ), | |
| .valid_o ( mst_req_o.ar_valid ), | |
| .ready_i ( mst_resp_i.ar_ready ), | |
| .data_o ( mst_req_o.ar ) | |
| ); | |
| for (genvar i = 0; i < NoSlvPorts; i++) begin : gen_slv_resps_r | |
| assign slv_resps_o[i].r = mst_r_chan; | |
| assign slv_resps_o[i].r_valid = mst_r_valid & ~r_fifo_empty & (r_select == select_t'(i)); | |
| end | |
| assign mst_r_ready = ~r_fifo_empty & slv_reqs_i[r_select].r_ready; | |
| assign r_fifo_pop = mst_r_valid & mst_r_ready; | |
| spill_register #( | |
| .T ( r_chan_t ), | |
| .Bypass ( ~SpillR ) | |
| ) i_r_spill_reg ( | |
| .clk_i ( clk_i ), | |
| .rst_ni ( rst_ni ), | |
| .valid_i ( mst_resp_i.r_valid ), | |
| .ready_o ( mst_req_o.r_ready ), | |
| .data_i ( mst_resp_i.r ), | |
| .valid_o ( mst_r_valid ), | |
| .ready_i ( mst_r_ready ), | |
| .data_o ( mst_r_chan ) | |
| ); | |
| end | |
| endmodule | |
| module axi_lite_mux_intf #( | |
| parameter int unsigned AxiAddrWidth = 32'd0, | |
| parameter int unsigned AxiDataWidth = 32'd0, | |
| parameter int unsigned NoSlvPorts = 32'd0, | |
| parameter int unsigned MaxTrans = 32'd0, | |
| parameter bit FallThrough = 1'b0, | |
| parameter bit SpillAw = 1'b1, | |
| parameter bit SpillW = 1'b0, | |
| parameter bit SpillB = 1'b0, | |
| parameter bit SpillAr = 1'b1, | |
| parameter bit SpillR = 1'b0 | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input logic test_i, | |
| AXI_LITE.Slave slv [NoSlvPorts-1:0], | |
| AXI_LITE.Master mst | |
| ); | |
| typedef logic [AxiAddrWidth-1:0] addr_t; | |
| typedef logic [AxiDataWidth-1:0] data_t; | |
| typedef logic [AxiDataWidth/8-1:0] strb_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_t r; | |
| logic r_valid; | |
| } axi_resp_t; | |
| axi_req_t [NoSlvPorts-1:0] slv_reqs; | |
| axi_resp_t [NoSlvPorts-1:0] slv_resps; | |
| axi_req_t mst_req; | |
| axi_resp_t mst_resp; | |
| for (genvar i = 0; i < NoSlvPorts; i++) begin : gen_assign_slv_ports | |
| assign slv_reqs[i].aw.addr = slv[i].aw_addr; | |
| assign slv_reqs[i].aw.prot = slv[i].aw_prot; | |
| assign slv_reqs[i].aw_valid = slv[i].aw_valid; | |
| assign slv_reqs[i].w.data = slv[i].w_data; | |
| assign slv_reqs[i].w.strb = slv[i].w_strb; | |
| assign slv_reqs[i].w_valid = slv[i].w_valid; | |
| assign slv_reqs[i].b_ready = slv[i].b_ready; | |
| assign slv_reqs[i].ar.addr = slv[i].ar_addr; | |
| assign slv_reqs[i].ar.prot = slv[i].ar_prot; | |
| assign slv_reqs[i].ar_valid = slv[i].ar_valid; | |
| assign slv_reqs[i].r_ready = slv[i].r_ready; | |
| assign slv[i].aw_ready = slv_resps[i].aw_ready; | |
| assign slv[i].ar_ready = slv_resps[i].ar_ready; | |
| assign slv[i].w_ready = slv_resps[i].w_ready; | |
| assign slv[i].b_valid = slv_resps[i].b_valid; | |
| assign slv[i].b_resp = slv_resps[i].b.resp; | |
| assign slv[i].r_valid = slv_resps[i].r_valid; | |
| assign slv[i].r_data = slv_resps[i].r.data; | |
| assign slv[i].r_resp = slv_resps[i].r.resp; | |
| end | |
| assign mst.aw_addr = mst_req.aw.addr; | |
| assign mst.aw_prot = mst_req.aw.prot; | |
| assign mst.aw_valid = mst_req.aw_valid; | |
| assign mst.w_data = mst_req.w.data; | |
| assign mst.w_strb = mst_req.w.strb; | |
| assign mst.w_valid = mst_req.w_valid; | |
| assign mst.b_ready = mst_req.b_ready; | |
| assign mst.ar_addr = mst_req.ar.addr; | |
| assign mst.ar_prot = mst_req.ar.prot; | |
| assign mst.ar_valid = mst_req.ar_valid; | |
| assign mst.r_ready = mst_req.r_ready; | |
| assign mst_resp.aw_ready = mst.aw_ready; | |
| assign mst_resp.ar_ready = mst.ar_ready; | |
| assign mst_resp.w_ready = mst.w_ready; | |
| assign mst_resp.b_valid = mst.b_valid; | |
| assign mst_resp.b.resp = mst.b_resp; | |
| assign mst_resp.r_valid = mst.r_valid; | |
| assign mst_resp.r.data = mst.r_data; | |
| assign mst_resp.r.resp = mst.r_resp; | |
| axi_lite_mux #( | |
| .aw_chan_t ( aw_chan_t ), | |
| .w_chan_t ( w_chan_t ), | |
| .b_chan_t ( b_chan_t ), | |
| .ar_chan_t ( ar_chan_t ), | |
| .r_chan_t ( r_chan_t ), | |
| .axi_req_t ( axi_req_t ), | |
| .axi_resp_t ( axi_resp_t ), | |
| .NoSlvPorts ( NoSlvPorts ), | |
| .MaxTrans ( MaxTrans ), | |
| .FallThrough ( FallThrough ), | |
| .SpillAw ( SpillAw ), | |
| .SpillW ( SpillW ), | |
| .SpillB ( SpillB ), | |
| .SpillAr ( SpillAr ), | |
| .SpillR ( SpillR ) | |
| ) i_axi_mux ( | |
| .clk_i, | |
| .rst_ni, | |
| .test_i, | |
| .slv_reqs_i ( slv_reqs ), | |
| .slv_resps_o ( slv_resps ), | |
| .mst_req_o ( mst_req ), | |
| .mst_resp_i ( mst_resp ) | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_regs #( | |
| parameter int unsigned RegNumBytes = 32'd0, | |
| parameter int unsigned AxiAddrWidth = 32'd0, | |
| parameter int unsigned AxiDataWidth = 32'd0, | |
| parameter bit PrivProtOnly = 1'b0, | |
| parameter bit SecuProtOnly = 1'b0, | |
| parameter logic [RegNumBytes-1:0] AxiReadOnly = {RegNumBytes{1'b0}}, | |
| parameter type byte_t = logic [7:0], | |
| parameter byte_t [RegNumBytes-1:0] RegRstVal = {RegNumBytes{8'h00}}, | |
| parameter type req_lite_t = logic, | |
| parameter type resp_lite_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input req_lite_t axi_req_i, | |
| output resp_lite_t axi_resp_o, | |
| output logic [RegNumBytes-1:0] wr_active_o, | |
| output logic [RegNumBytes-1:0] rd_active_o, | |
| input byte_t [RegNumBytes-1:0] reg_d_i, | |
| input logic [RegNumBytes-1:0] reg_load_i, | |
| output byte_t [RegNumBytes-1:0] reg_q_o | |
| ); | |
| localparam int unsigned AxiStrbWidth = AxiDataWidth / 32'd8; | |
| localparam int unsigned NumChunks = cf_math_pkg::ceil_div(RegNumBytes, AxiStrbWidth); | |
| localparam int unsigned ChunkIdxWidth = (NumChunks > 32'd1) ? $clog2(NumChunks) : 32'd1; | |
| typedef logic [ChunkIdxWidth-1:0] chunk_idx_t; | |
| localparam int unsigned AddrWidth = (RegNumBytes > 32'd1) ? ($clog2(RegNumBytes)+1) : 32'd2; | |
| typedef logic [AddrWidth-1:0] addr_t; | |
| typedef struct packed { | |
| int unsigned idx; | |
| addr_t start_addr; | |
| addr_t end_addr; | |
| } axi_rule_t; | |
| axi_rule_t [NumChunks-1:0] addr_map; | |
| for (genvar i = 0; i < NumChunks; i++) begin : gen_addr_map | |
| assign addr_map[i] = axi_rule_t'{ | |
| idx: i, | |
| start_addr: addr_t'( i * AxiStrbWidth), | |
| end_addr: addr_t'((i+1)* AxiStrbWidth) | |
| }; | |
| end | |
| typedef logic [AxiDataWidth-1:0] axi_data_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_lite_t; | |
| typedef struct packed { | |
| axi_data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_lite_t; | |
| byte_t [RegNumBytes-1:0] reg_q, reg_d; | |
| logic [RegNumBytes-1:0] reg_update; | |
| chunk_idx_t aw_chunk_idx; | |
| logic aw_dec_valid; | |
| b_chan_lite_t b_chan; | |
| logic b_valid, b_ready; | |
| logic aw_prot_ok; | |
| logic chunk_loaded, chunk_ro; | |
| assign aw_prot_ok = (PrivProtOnly ? axi_req_i.aw.prot[0] : 1'b1) & | |
| (SecuProtOnly ? axi_req_i.aw.prot[1] : 1'b1); | |
| logic [AxiStrbWidth-1:0] load; | |
| logic [AxiStrbWidth-1:0] read_only; | |
| addr_t byte_w_addr; | |
| assign byte_w_addr = addr_t'(aw_chunk_idx * AxiStrbWidth); | |
| for (genvar i = 0; i < AxiStrbWidth; i++) begin : gen_load_assign | |
| addr_t reg_w_idx; | |
| assign reg_w_idx = byte_w_addr + addr_t'(i); | |
| assign load[i] = (reg_w_idx < RegNumBytes) ? | |
| (reg_load_i[reg_w_idx] && !AxiReadOnly[reg_w_idx]) : 1'b0; | |
| assign read_only[i] = (reg_w_idx < RegNumBytes) ? AxiReadOnly[reg_w_idx] : 1'b1; | |
| end | |
| assign chunk_loaded = |(load & axi_req_i.w.strb); | |
| assign chunk_ro = &read_only; | |
| always_comb begin | |
| automatic addr_t reg_byte_idx = '0; | |
| reg_d = reg_q; | |
| reg_update = '0; | |
| axi_resp_o.aw_ready = 1'b0; | |
| axi_resp_o.w_ready = 1'b0; | |
| b_chan = b_chan_lite_t'{resp: axi_pkg::RESP_SLVERR, default: '0}; | |
| b_valid = 1'b0; | |
| wr_active_o = '0; | |
| for (int unsigned i = 0; i < RegNumBytes; i++) begin | |
| if (reg_load_i[i]) begin | |
| reg_d[i] = reg_d_i[i]; | |
| reg_update[i] = 1'b1; | |
| end | |
| end | |
| if (axi_req_i.aw_valid && axi_req_i.w_valid && b_ready) begin | |
| if (aw_dec_valid && aw_prot_ok) begin | |
| if (!chunk_loaded) begin | |
| for (int unsigned i = 0; i < AxiStrbWidth; i++) begin | |
| reg_byte_idx = byte_w_addr + addr_t'(i); | |
| if (reg_byte_idx < RegNumBytes) begin | |
| if (!AxiReadOnly[reg_byte_idx] && axi_req_i.w.strb[i]) begin | |
| reg_d[reg_byte_idx] = axi_req_i.w.data[8*i+:8]; | |
| reg_update[reg_byte_idx] = 1'b1; | |
| end | |
| wr_active_o[reg_byte_idx] = axi_req_i.w.strb[i]; | |
| end | |
| end | |
| b_chan.resp = chunk_ro ? axi_pkg::RESP_SLVERR : axi_pkg::RESP_OKAY; | |
| b_valid = 1'b1; | |
| axi_resp_o.aw_ready = 1'b1; | |
| axi_resp_o.w_ready = 1'b1; | |
| end | |
| end else begin | |
| b_valid = 1'b1; | |
| axi_resp_o.aw_ready = 1'b1; | |
| axi_resp_o.w_ready = 1'b1; | |
| end | |
| end | |
| end | |
| chunk_idx_t ar_chunk_idx; | |
| logic ar_dec_valid; | |
| r_chan_lite_t r_chan; | |
| logic r_valid, r_ready; | |
| logic ar_prot_ok; | |
| assign ar_prot_ok = (PrivProtOnly ? axi_req_i.ar.prot[0] : 1'b1) & | |
| (SecuProtOnly ? axi_req_i.ar.prot[1] : 1'b1); | |
| always_comb begin | |
| automatic int unsigned reg_byte_idx = '0; | |
| r_chan = r_chan_lite_t'{ | |
| data: axi_data_t'(32'hBA5E1E55), | |
| resp: axi_pkg::RESP_SLVERR, | |
| default: '0 | |
| }; | |
| rd_active_o = '0; | |
| if (ar_dec_valid && ar_prot_ok) begin | |
| for (int unsigned i = 0; i < AxiStrbWidth; i++) begin | |
| reg_byte_idx = unsigned'(ar_chunk_idx) * AxiStrbWidth + i; | |
| if (reg_byte_idx < RegNumBytes) begin | |
| r_chan.data[8*i+:8] = reg_q_o[reg_byte_idx]; | |
| rd_active_o[reg_byte_idx] = r_valid & r_ready; | |
| end else begin | |
| r_chan.data[8*i+:8] = 8'h00; | |
| end | |
| end | |
| r_chan.resp = axi_pkg::RESP_OKAY; | |
| end | |
| end | |
| assign r_valid = axi_req_i.ar_valid; | |
| assign axi_resp_o.ar_ready = r_ready; | |
| for (genvar i = 0; i < RegNumBytes; i++) begin : gen_rw_regs | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| reg_q[i] <= (RegRstVal[i]); | |
| end else begin | |
| if (reg_update[i]) begin | |
| reg_q[i] <= (reg_d[i]); | |
| end | |
| end | |
| end | |
| assign reg_q_o[i] = reg_q[i]; | |
| end | |
| addr_decode #( | |
| .NoIndices ( NumChunks ), | |
| .NoRules ( NumChunks ), | |
| .addr_t ( addr_t ), | |
| .rule_t ( axi_rule_t ) | |
| ) i_aw_decode ( | |
| .addr_i ( addr_t'(axi_req_i.aw.addr) ), | |
| .addr_map_i ( addr_map ), | |
| .idx_o ( aw_chunk_idx ), | |
| .dec_valid_o ( aw_dec_valid ), | |
| .dec_error_o ( ), | |
| .en_default_idx_i ( '0 ), | |
| .default_idx_i ( '0 ) | |
| ); | |
| addr_decode #( | |
| .NoIndices ( NumChunks ), | |
| .NoRules ( NumChunks ), | |
| .addr_t ( addr_t ), | |
| .rule_t ( axi_rule_t ) | |
| ) i_ar_decode ( | |
| .addr_i ( addr_t'(axi_req_i.ar.addr) ), | |
| .addr_map_i ( addr_map ), | |
| .idx_o ( ar_chunk_idx ), | |
| .dec_valid_o ( ar_dec_valid ), | |
| .dec_error_o ( ), | |
| .en_default_idx_i ( '0 ), | |
| .default_idx_i ( '0 ) | |
| ); | |
| spill_register #( | |
| .T ( b_chan_lite_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_b_spill_register ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( b_valid ), | |
| .ready_o ( b_ready ), | |
| .data_i ( b_chan ), | |
| .valid_o ( axi_resp_o.b_valid ), | |
| .ready_i ( axi_req_i.b_ready ), | |
| .data_o ( axi_resp_o.b ) | |
| ); | |
| spill_register #( | |
| .T ( r_chan_lite_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_r_spill_register ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( r_valid ), | |
| .ready_o ( r_ready ), | |
| .data_i ( r_chan ), | |
| .valid_o ( axi_resp_o.r_valid ), | |
| .ready_i ( axi_req_i.r_ready ), | |
| .data_o ( axi_resp_o.r ) | |
| ); | |
| endmodule | |
| module axi_lite_regs_intf #( | |
| parameter type byte_t = logic [7:0], | |
| parameter int unsigned REG_NUM_BYTES = 32'd0, | |
| parameter int unsigned AXI_ADDR_WIDTH = 32'd0, | |
| parameter int unsigned AXI_DATA_WIDTH = 32'd0, | |
| parameter bit PRIV_PROT_ONLY = 1'd0, | |
| parameter bit SECU_PROT_ONLY = 1'd0, | |
| parameter logic [REG_NUM_BYTES-1:0] AXI_READ_ONLY = {REG_NUM_BYTES{1'b0}}, | |
| parameter byte_t [REG_NUM_BYTES-1:0] REG_RST_VAL = {REG_NUM_BYTES{8'h00}} | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| AXI_LITE.Slave slv, | |
| output logic [REG_NUM_BYTES-1:0] wr_active_o, | |
| output logic [REG_NUM_BYTES-1:0] rd_active_o, | |
| input byte_t [REG_NUM_BYTES-1:0] reg_d_i, | |
| input logic [REG_NUM_BYTES-1:0] reg_load_i, | |
| output byte_t [REG_NUM_BYTES-1:0] reg_q_o | |
| ); | |
| typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; | |
| typedef logic [AXI_DATA_WIDTH-1:0] data_t; | |
| typedef logic [AXI_DATA_WIDTH/8-1:0] strb_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_lite_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_lite_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_lite_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_lite_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_lite_t; | |
| typedef struct packed { | |
| aw_chan_lite_t aw; | |
| logic aw_valid; | |
| w_chan_lite_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_lite_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } req_lite_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_lite_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_lite_t r; | |
| logic r_valid; | |
| } resp_lite_t; | |
| req_lite_t axi_lite_req; | |
| resp_lite_t axi_lite_resp; | |
| assign axi_lite_req.aw.addr = slv.aw_addr; | |
| assign axi_lite_req.aw.prot = slv.aw_prot; | |
| assign axi_lite_req.aw_valid = slv.aw_valid; | |
| assign axi_lite_req.w.data = slv.w_data; | |
| assign axi_lite_req.w.strb = slv.w_strb; | |
| assign axi_lite_req.w_valid = slv.w_valid; | |
| assign axi_lite_req.b_ready = slv.b_ready; | |
| assign axi_lite_req.ar.addr = slv.ar_addr; | |
| assign axi_lite_req.ar.prot = slv.ar_prot; | |
| assign axi_lite_req.ar_valid = slv.ar_valid; | |
| assign axi_lite_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = axi_lite_resp.aw_ready; | |
| assign slv.ar_ready = axi_lite_resp.ar_ready; | |
| assign slv.w_ready = axi_lite_resp.w_ready; | |
| assign slv.b_valid = axi_lite_resp.b_valid; | |
| assign slv.b_resp = axi_lite_resp.b.resp; | |
| assign slv.r_valid = axi_lite_resp.r_valid; | |
| assign slv.r_data = axi_lite_resp.r.data; | |
| assign slv.r_resp = axi_lite_resp.r.resp; | |
| axi_lite_regs #( | |
| .RegNumBytes ( REG_NUM_BYTES ), | |
| .AxiAddrWidth ( AXI_ADDR_WIDTH ), | |
| .AxiDataWidth ( AXI_DATA_WIDTH ), | |
| .PrivProtOnly ( PRIV_PROT_ONLY ), | |
| .SecuProtOnly ( SECU_PROT_ONLY ), | |
| .AxiReadOnly ( AXI_READ_ONLY ), | |
| .RegRstVal ( REG_RST_VAL ), | |
| .req_lite_t ( req_lite_t ), | |
| .resp_lite_t ( resp_lite_t ) | |
| ) i_axi_lite_regs ( | |
| .clk_i, | |
| .rst_ni, | |
| .axi_req_i ( axi_lite_req ), | |
| .axi_resp_o ( axi_lite_resp ), | |
| .wr_active_o, | |
| .rd_active_o, | |
| .reg_d_i, | |
| .reg_load_i, | |
| .reg_q_o | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_to_apb #( | |
| parameter int unsigned NoApbSlaves = 32'd1, | |
| parameter int unsigned NoRules = 32'd1, | |
| parameter int unsigned AddrWidth = 32'd32, | |
| parameter int unsigned DataWidth = 32'd32, | |
| parameter bit PipelineRequest = 1'b0, | |
| parameter bit PipelineResponse = 1'b0, | |
| parameter type axi_lite_req_t = logic, | |
| parameter type axi_lite_resp_t = logic, | |
| parameter type apb_req_t = logic, | |
| parameter type apb_resp_t = logic, | |
| parameter type rule_t = logic | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| input axi_lite_req_t axi_lite_req_i, | |
| output axi_lite_resp_t axi_lite_resp_o, | |
| output apb_req_t [NoApbSlaves-1:0] apb_req_o, | |
| input apb_resp_t [NoApbSlaves-1:0] apb_resp_i, | |
| input rule_t [NoRules-1:0] addr_map_i | |
| ); | |
| localparam logic RD = 1'b0; | |
| localparam logic WR = 1'b1; | |
| localparam int unsigned SelIdxWidth = (NoApbSlaves > 32'd1) ? $clog2(NoApbSlaves) : 32'd1; | |
| typedef logic [AddrWidth-1:0] addr_t; | |
| typedef logic [DataWidth-1:0] data_t; | |
| typedef logic [DataWidth/8-1:0] strb_t; | |
| typedef logic [SelIdxWidth-1:0] sel_idx_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| data_t data; | |
| strb_t strb; | |
| logic write; | |
| } int_req_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } int_resp_t; | |
| typedef enum logic { | |
| Setup = 1'b0, | |
| Access = 1'b1 | |
| } apb_state_e; | |
| int_req_t [1:0] axi_req; | |
| logic [1:0] axi_req_valid, axi_req_ready; | |
| axi_pkg::resp_t axi_bresp; | |
| logic axi_bresp_valid, axi_bresp_ready; | |
| int_resp_t axi_rresp; | |
| logic axi_rresp_valid, axi_rresp_ready; | |
| assign axi_req[RD] = '{ | |
| addr: axi_lite_req_i.ar.addr, | |
| prot: axi_lite_req_i.ar.prot, | |
| data: '0, | |
| strb: '0, | |
| write: RD | |
| }; | |
| assign axi_req_valid[RD] = axi_lite_req_i.ar_valid; | |
| assign axi_req[WR] = '{ | |
| addr: axi_lite_req_i.aw.addr, | |
| prot: axi_lite_req_i.aw.prot, | |
| data: axi_lite_req_i.w.data, | |
| strb: axi_lite_req_i.w.strb, | |
| write: WR | |
| }; | |
| assign axi_req_valid[WR] = axi_lite_req_i.aw_valid & axi_lite_req_i.w_valid; | |
| assign axi_lite_resp_o = '{ | |
| aw_ready: axi_req_valid[WR] & axi_req_ready[WR], | |
| w_ready: axi_req_valid[WR] & axi_req_ready[WR], | |
| b: '{resp: axi_bresp}, | |
| b_valid: axi_bresp_valid, | |
| ar_ready: axi_req_valid[RD] & axi_req_ready[RD], | |
| r: '{data: axi_rresp.data, resp: axi_rresp.resp}, | |
| r_valid: axi_rresp_valid | |
| }; | |
| int_req_t arb_req, apb_req; | |
| logic arb_req_valid, arb_req_ready, apb_req_valid, apb_req_ready; | |
| axi_pkg::resp_t apb_wresp; | |
| logic apb_wresp_valid, apb_wresp_ready; | |
| int_resp_t apb_rresp; | |
| logic apb_rresp_valid, apb_rresp_ready; | |
| rr_arb_tree #( | |
| .NumIn ( 32'd2 ), | |
| .DataType ( int_req_t ), | |
| .ExtPrio ( 1'b0 ), | |
| .AxiVldRdy( 1'b1 ), | |
| .LockIn ( 1'b1 ) | |
| ) i_req_arb ( | |
| .clk_i, | |
| .rst_ni, | |
| .flush_i ( '0 ), | |
| .rr_i ( '0 ), | |
| .req_i ( axi_req_valid ), | |
| .gnt_o ( axi_req_ready ), | |
| .data_i ( axi_req ), | |
| .gnt_i ( arb_req_ready ), | |
| .req_o ( arb_req_valid ), | |
| .data_o ( arb_req ), | |
| .idx_o ( ) | |
| ); | |
| if (PipelineRequest) begin : gen_req_spill | |
| spill_register #( | |
| .T ( int_req_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_req_spill ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( arb_req_valid ), | |
| .ready_o ( arb_req_ready ), | |
| .data_i ( arb_req ), | |
| .valid_o ( apb_req_valid ), | |
| .ready_i ( apb_req_ready ), | |
| .data_o ( apb_req ) | |
| ); | |
| end else begin : gen_req_ft_reg | |
| fall_through_register #( | |
| .T ( int_req_t ) | |
| ) i_req_ft_reg ( | |
| .clk_i, | |
| .rst_ni, | |
| .clr_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .valid_i ( arb_req_valid ), | |
| .ready_o ( arb_req_ready ), | |
| .data_i ( arb_req ), | |
| .valid_o ( apb_req_valid ), | |
| .ready_i ( apb_req_ready ), | |
| .data_o ( apb_req ) | |
| ); | |
| end | |
| if (PipelineResponse) begin : gen_resp_spill | |
| spill_register #( | |
| .T ( axi_pkg::resp_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_write_resp_spill ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( apb_wresp_valid ), | |
| .ready_o ( apb_wresp_ready ), | |
| .data_i ( apb_wresp ), | |
| .valid_o ( axi_bresp_valid ), | |
| .ready_i ( axi_lite_req_i.b_ready ), | |
| .data_o ( axi_bresp ) | |
| ); | |
| spill_register #( | |
| .T ( int_resp_t ), | |
| .Bypass ( 1'b0 ) | |
| ) i_read_resp_spill ( | |
| .clk_i, | |
| .rst_ni, | |
| .valid_i ( apb_rresp_valid ), | |
| .ready_o ( apb_rresp_ready ), | |
| .data_i ( apb_rresp ), | |
| .valid_o ( axi_rresp_valid ), | |
| .ready_i ( axi_lite_req_i.r_ready ), | |
| .data_o ( axi_rresp ) | |
| ); | |
| end else begin : gen_resp_ft_reg | |
| fall_through_register #( | |
| .T ( axi_pkg::resp_t ) | |
| ) i_write_resp_ft_reg ( | |
| .clk_i, | |
| .rst_ni, | |
| .clr_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .valid_i ( apb_wresp_valid ), | |
| .ready_o ( apb_wresp_ready ), | |
| .data_i ( apb_wresp ), | |
| .valid_o ( axi_bresp_valid ), | |
| .ready_i ( axi_lite_req_i.b_ready ), | |
| .data_o ( axi_bresp ) | |
| ); | |
| fall_through_register #( | |
| .T ( int_resp_t ) | |
| ) i_read_resp_ft_reg ( | |
| .clk_i, | |
| .rst_ni, | |
| .clr_i ( 1'b0 ), | |
| .testmode_i ( 1'b0 ), | |
| .valid_i ( apb_rresp_valid ), | |
| .ready_o ( apb_rresp_ready ), | |
| .data_i ( apb_rresp ), | |
| .valid_o ( axi_rresp_valid ), | |
| .ready_i ( axi_lite_req_i.r_ready ), | |
| .data_o ( axi_rresp ) | |
| ); | |
| end | |
| apb_state_e apb_state_q, apb_state_d; | |
| logic apb_update; | |
| logic apb_dec_valid; | |
| sel_idx_t apb_sel_idx; | |
| addr_decode #( | |
| .NoIndices( NoApbSlaves ), | |
| .NoRules ( NoRules ), | |
| .addr_t ( addr_t ), | |
| .rule_t ( rule_t ) | |
| ) i_apb_decode ( | |
| .addr_i ( apb_req.addr ), | |
| .addr_map_i ( addr_map_i ), | |
| .idx_o ( apb_sel_idx ), | |
| .dec_valid_o ( apb_dec_valid ), | |
| .dec_error_o ( ), | |
| .en_default_idx_i ( '0 ), | |
| .default_idx_i ( '0 ) | |
| ); | |
| always_comb begin | |
| apb_state_d = apb_state_q; | |
| apb_update = 1'b0; | |
| apb_req_o = '0; | |
| apb_req_ready = 1'b0; | |
| apb_wresp = axi_pkg::RESP_SLVERR; | |
| apb_wresp_valid = 1'b0; | |
| apb_rresp = '{data: data_t'(32'hDEA110C8), resp: axi_pkg::RESP_SLVERR}; | |
| apb_rresp_valid = 1'b0; | |
| unique case (apb_state_q) | |
| Setup: begin | |
| if (apb_req_valid && apb_wresp_ready && apb_rresp_ready) begin | |
| if (apb_dec_valid && ((apb_req.write && (|apb_req.strb)) || (!apb_req.write))) begin | |
| apb_req_o[apb_sel_idx] = '{ | |
| paddr: axi_pkg::aligned_addr(axi_pkg::largest_addr_t'(apb_req.addr), $clog2(DataWidth/8)), | |
| pprot: apb_req.prot, | |
| psel: 1'b1, | |
| penable: 1'b0, | |
| pwrite: apb_req.write, | |
| pwdata: apb_req.data, | |
| pstrb: apb_req.strb | |
| }; | |
| apb_state_d = Access; | |
| apb_update = 1'b1; | |
| end else begin | |
| apb_req_ready = 1'b1; | |
| if (apb_req.write) begin | |
| apb_wresp = ~(|apb_req.strb) ? axi_pkg::RESP_OKAY : axi_pkg::RESP_DECERR; | |
| apb_wresp_valid = 1'b1; | |
| end else begin | |
| apb_rresp.resp = axi_pkg::RESP_DECERR; | |
| apb_rresp_valid = 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| Access: begin | |
| apb_req_o[apb_sel_idx] = '{ | |
| paddr: axi_pkg::aligned_addr(axi_pkg::largest_addr_t'(apb_req.addr), $clog2(DataWidth/8)), | |
| pprot: apb_req.prot, | |
| psel: 1'b1, | |
| penable: 1'b1, | |
| pwrite: apb_req.write, | |
| pwdata: apb_req.data, | |
| pstrb: apb_req.strb | |
| }; | |
| if (apb_resp_i[apb_sel_idx].pready) begin | |
| apb_req_ready = 1'b1; | |
| if (apb_req.write) begin | |
| apb_wresp = apb_resp_i[apb_sel_idx].pslverr ? | |
| axi_pkg::RESP_SLVERR : axi_pkg::RESP_OKAY; | |
| apb_wresp_valid = 1'b1; | |
| end else begin | |
| apb_rresp.data = apb_resp_i[apb_sel_idx].prdata; | |
| apb_rresp.resp = apb_resp_i[apb_sel_idx].pslverr ? | |
| axi_pkg::RESP_SLVERR : axi_pkg::RESP_OKAY; | |
| apb_rresp_valid = 1'b1; | |
| end | |
| apb_state_d = Setup; | |
| apb_update = 1'b1; | |
| end | |
| end | |
| default: ; | |
| endcase | |
| end | |
| always_ff @(posedge (clk_i) or negedge (rst_ni)) begin | |
| if (!rst_ni) begin | |
| apb_state_q <= (Setup); | |
| end else begin | |
| if (apb_update) begin | |
| apb_state_q <= (apb_state_d); | |
| end | |
| end | |
| end | |
| endmodule | |
| module axi_lite_to_apb_intf #( | |
| parameter int unsigned NoApbSlaves = 32'd1, | |
| parameter int unsigned NoRules = 32'd1, | |
| parameter int unsigned AddrWidth = 32'd32, | |
| parameter int unsigned DataWidth = 32'd32, | |
| parameter bit PipelineRequest = 1'b0, | |
| parameter bit PipelineResponse = 1'b0, | |
| parameter type rule_t = logic, | |
| parameter type addr_t = logic [AddrWidth-1:0], | |
| parameter type data_t = logic [DataWidth-1:0], | |
| parameter type strb_t = logic [DataWidth/8-1:0], | |
| parameter type sel_t = logic [NoApbSlaves-1:0] | |
| ) ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| AXI_LITE.Slave slv, | |
| output addr_t paddr_o, | |
| output logic [2:0] pprot_o, | |
| output sel_t pselx_o, | |
| output logic penable_o, | |
| output logic pwrite_o, | |
| output data_t pwdata_o, | |
| output strb_t pstrb_o, | |
| input logic [NoApbSlaves-1:0] pready_i, | |
| input data_t [NoApbSlaves-1:0] prdata_i, | |
| input [NoApbSlaves-1:0] pslverr_i, | |
| input rule_t [NoRules-1:0] addr_map_i | |
| ); | |
| localparam int unsigned SelIdxWidth = NoApbSlaves > 1 ? $clog2(NoApbSlaves) : 1; | |
| typedef struct packed { | |
| addr_t paddr; | |
| axi_pkg::prot_t pprot; | |
| logic psel; | |
| logic penable; | |
| logic pwrite; | |
| data_t pwdata; | |
| strb_t pstrb; | |
| } apb_req_t; | |
| typedef struct packed { | |
| logic pready; | |
| data_t prdata; | |
| logic pslverr; | |
| } apb_resp_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } aw_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| strb_t strb; | |
| } w_chan_t; | |
| typedef struct packed { | |
| axi_pkg::resp_t resp; | |
| } b_chan_t; | |
| typedef struct packed { | |
| addr_t addr; | |
| axi_pkg::prot_t prot; | |
| } ar_chan_t; | |
| typedef struct packed { | |
| data_t data; | |
| axi_pkg::resp_t resp; | |
| } r_chan_t; | |
| typedef struct packed { | |
| aw_chan_t aw; | |
| logic aw_valid; | |
| w_chan_t w; | |
| logic w_valid; | |
| logic b_ready; | |
| ar_chan_t ar; | |
| logic ar_valid; | |
| logic r_ready; | |
| } axi_req_t; | |
| typedef struct packed { | |
| logic aw_ready; | |
| logic w_ready; | |
| b_chan_t b; | |
| logic b_valid; | |
| logic ar_ready; | |
| r_chan_t r; | |
| logic r_valid; | |
| } axi_resp_t; | |
| axi_req_t axi_req; | |
| axi_resp_t axi_resp; | |
| apb_req_t [NoApbSlaves-1:0] apb_req; | |
| apb_resp_t [NoApbSlaves-1:0] apb_resp; | |
| logic [SelIdxWidth-1:0] apb_sel; | |
| assign axi_req.aw.addr = slv.aw_addr; | |
| assign axi_req.aw.prot = slv.aw_prot; | |
| assign axi_req.aw_valid = slv.aw_valid; | |
| assign axi_req.w.data = slv.w_data; | |
| assign axi_req.w.strb = slv.w_strb; | |
| assign axi_req.w_valid = slv.w_valid; | |
| assign axi_req.b_ready = slv.b_ready; | |
| assign axi_req.ar.addr = slv.ar_addr; | |
| assign axi_req.ar.prot = slv.ar_prot; | |
| assign axi_req.ar_valid = slv.ar_valid; | |
| assign axi_req.r_ready = slv.r_ready; | |
| assign slv.aw_ready = axi_resp.aw_ready; | |
| assign slv.ar_ready = axi_resp.ar_ready; | |
| assign slv.w_ready = axi_resp.w_ready; | |
| assign slv.b_valid = axi_resp.b_valid; | |
| assign slv.b_resp = axi_resp.b.resp; | |
| assign slv.r_valid = axi_resp.r_valid; | |
| assign slv.r_data = axi_resp.r.data; | |
| assign slv.r_resp = axi_resp.r.resp; | |
| onehot_to_bin #( | |
| .ONEHOT_WIDTH ( NoApbSlaves ) | |
| ) i_onehot_to_bin ( | |
| .onehot ( pselx_o ), | |
| .bin ( apb_sel ) | |
| ); | |
| assign paddr_o = apb_req[apb_sel].paddr; | |
| assign pprot_o = apb_req[apb_sel].pprot; | |
| assign penable_o = apb_req[apb_sel].penable; | |
| assign pwrite_o = apb_req[apb_sel].pwrite; | |
| assign pwdata_o = apb_req[apb_sel].pwdata; | |
| assign pstrb_o = apb_req[apb_sel].pstrb; | |
| for (genvar i = 0; i < NoApbSlaves; i++) begin : gen_apb_resp_assign | |
| assign pselx_o[i] = apb_req[i].psel; | |
| assign apb_resp[i].pready = pready_i[i]; | |
| assign apb_resp[i].prdata = prdata_i[i]; | |
| assign apb_resp[i].pslverr = pslverr_i[i]; | |
| end | |
| axi_lite_to_apb #( | |
| .NoApbSlaves ( NoApbSlaves ), | |
| .NoRules ( NoRules ), | |
| .AddrWidth ( AddrWidth ), | |
| .DataWidth ( DataWidth ), | |
| .PipelineRequest ( PipelineRequest ), | |
| .PipelineResponse ( PipelineResponse ), | |
| .axi_lite_req_t ( axi_req_t ), | |
| .axi_lite_resp_t ( axi_resp_t ), | |
| .apb_req_t ( apb_req_t ), | |
| .apb_resp_t ( apb_resp_t ), | |
| .rule_t ( rule_t ) | |
| ) i_axi_lite_to_apb ( | |
| .clk_i, | |
| .rst_ni, | |
| .axi_lite_req_i ( axi_req ), | |
| .axi_lite_resp_o ( axi_resp ), | |
| .apb_req_o ( apb_req ), | |
| .apb_resp_i ( apb_resp ), | |
| .addr_map_i | |
| ); | |
| endmodule | |
| `begin_keywords "1800-2023" | |
| module axi_lite_to_axi #( | |
| parameter int unsigned AxiDataWidth = 32'd0, | |
| parameter type req_lite_t = logic, | |
| parameter type resp_lite_t = logic, | |
| parameter type axi_req_t = logic, | |
| parameter type axi_resp_t = logic | |
| ) ( | |
| input req_lite_t slv_req_lite_i, | |
| output resp_lite_t slv_resp_lite_o, | |
| input axi_pkg::cache_t slv_aw_cache_i, | |
| input axi_pkg::cache_t slv_ar_cache_i, | |
| output axi_req_t mst_req_o, | |
| input axi_resp_t mst_resp_i | |
| ); | |
| localparam int unsigned AxiSize = axi_pkg::size_t'($unsigned($clog2(AxiDataWidth/8))); | |
| assign mst_req_o = '{ | |
| aw: '{ | |
| addr: slv_req_lite_i.aw.addr, | |
| prot: slv_req_lite_i.aw.prot, | |
| size: AxiSize, | |
| burst: axi_pkg::BURST_FIXED, | |
| cache: slv_aw_cache_i, | |
| default: '0 | |
| }, | |
| aw_valid: slv_req_lite_i.aw_valid, | |
| w: '{ | |
| data: slv_req_lite_i.w.data, | |
| strb: slv_req_lite_i.w.strb, | |
| last: 1'b1, | |
| default: '0 | |
| }, | |
| w_valid: slv_req_lite_i.w_valid, | |
| b_ready: slv_req_lite_i.b_ready, | |
| ar: '{ | |
| addr: slv_req_lite_i.ar.addr, | |
| prot: slv_req_lite_i.ar.prot, | |
| size: AxiSize, | |
| burst: axi_pkg::BURST_FIXED, | |
| cache: slv_ar_cache_i, | |
| default: '0 | |
| }, | |
| ar_valid: slv_req_lite_i.ar_valid, | |
| r_ready: slv_req_lite_i.r_ready, | |
| default: '0 | |
| }; | |
| assign slv_resp_lite_o = '{ | |
| aw_ready: mst_resp_i.aw_ready, | |
| w_ready: mst_resp_i.w_ready, | |
| b: '{ | |
| resp: mst_resp_i.b.resp, | |
| default: '0 | |
| }, | |
| b_valid: mst_resp_i.b_valid, | |
| ar_ready: mst_resp_i.ar_ready, | |
| r: '{ | |
| data: mst_resp_i.r.data, | |
| resp: mst_resp_i.r.resp, | |
| default: '0 | |
| }, | |
| r_valid: mst_resp_i.r_valid, | |
| default: '0 | |
| }; | |
| endmodule | |
| module axi_lite_to_axi_intf #( | |
| parameter int unsigned AXI_DATA_WIDTH = 32'd0 | |
| ) ( | |
| AXI_LITE.Slave in, | |
| input axi_pkg::cache_t slv_aw_cache_i, | |
| input axi_pkg::cache_t slv_ar_cache_i, | |
| AXI_BUS.Master out | |
| ); | |
| localparam int unsigned AxiSize = axi_pkg::size_t'($unsigned($clog2(AXI_DATA_WIDTH/8))); | |
| initial begin | |
| assert(in.AXI_ADDR_WIDTH == out.AXI_ADDR_WIDTH); | |
| assert(in.AXI_DATA_WIDTH == out.AXI_DATA_WIDTH); | |
| assert(AXI_DATA_WIDTH == out.AXI_DATA_WIDTH); | |
| end | |
| assign out.aw_id = '0; | |
| assign out.aw_addr = in.aw_addr; | |
| assign out.aw_len = '0; | |
| assign out.aw_size = axi_pkg::size_t'(AxiSize); | |
| assign out.aw_burst = axi_pkg::BURST_FIXED; | |
| assign out.aw_lock = '0; | |
| assign out.aw_cache = slv_aw_cache_i; | |
| assign out.aw_prot = '0; | |
| assign out.aw_qos = '0; | |
| assign out.aw_region = '0; | |
| assign out.aw_atop = '0; | |
| assign out.aw_user = '0; | |
| assign out.aw_valid = in.aw_valid; | |
| assign in.aw_ready = out.aw_ready; | |
| assign out.w_data = in.w_data; | |
| assign out.w_strb = in.w_strb; | |
| assign out.w_last = '1; | |
| assign out.w_user = '0; | |
| assign out.w_valid = in.w_valid; | |
| assign in.w_ready = out.w_ready; | |
| assign in.b_resp = out.b_resp; | |
| assign in.b_valid = out.b_valid; | |
| assign out.b_ready = in.b_ready; | |
| assign out.ar_id = '0; | |
| assign out.ar_addr = in.ar_addr; | |
| assign out.ar_len = '0; | |
| assign out.ar_size = axi_pkg::size_t'(AxiSize); | |
| assign out.ar_burst = axi_pkg::BURST_FIXED; | |
| assign out.ar_lock = '0; | |
| assign out.ar_cache = slv_ar_cache_i; | |
| assign out.ar_prot = '0; | |
| assign out.ar_qos = '0; | |
| assign o |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment