Vendorize CVA6 core submodules (common_cells, FPU with related sub-modules) (#1007)

This commit is contained in:
Zbigniew Chamski 2022-12-09 11:07:12 +01:00 committed by GitHub
parent b817386ff4
commit 8a5898dce4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
188 changed files with 25749 additions and 331 deletions

View file

@ -8,7 +8,7 @@ package:
# WT_DCACHE
export_include_dirs:
- common/submodules/common_cells/include/
- vendor/pulp-platform/common_cells/include/
- corev_apu/axi/include/
sources:
@ -28,8 +28,8 @@ sources:
- corev_apu/tb/ariane_axi_soc_pkg.sv
- core/include/ariane_axi_pkg.sv
- core/include/std_cache_pkg.sv
- core/fpu/src/fpnew_pkg.sv
- core/fpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
- vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
- vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
# Stand-alone source files
- core/ariane.sv
- core/serdiv.sv
@ -68,24 +68,24 @@ sources:
- core/issue_read_operands.sv
- core/pmp/src/pmp_entry.sv
- core/pmp/src/pmp.sv
- core/fpu/src/fpnew_fma.sv
- core/fpu/src/fpnew_opgroup_fmt_slice.sv
- core/fpu/src/fpnew_divsqrt_multi.sv
- core/fpu/src/fpnew_fma_multi.sv
- core/fpu/src/fpnew_opgroup_multifmt_slice.sv
- core/fpu/src/fpnew_classifier.sv
- core/fpu/src/fpnew_noncomp.sv
- core/fpu/src/fpnew_cast_multi.sv
- core/fpu/src/fpnew_opgroup_block.sv
- core/fpu/src/fpnew_rounding.sv
- core/fpu/src/fpnew_top.sv
- core/fpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
- core/fpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
- core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
- core/fpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
- core/fpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
- core/fpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
- core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_mvp_wrapper.sv
- vendor/pulp-platform/fpnew/src/fpnew_fma.sv
- vendor/pulp-platform/fpnew/src/fpnew_opgroup_fmt_slice.sv
- vendor/pulp-platform/fpnew/src/fpnew_divsqrt_multi.sv
- vendor/pulp-platform/fpnew/src/fpnew_fma_multi.sv
- vendor/pulp-platform/fpnew/src/fpnew_opgroup_multifmt_slice.sv
- vendor/pulp-platform/fpnew/src/fpnew_classifier.sv
- vendor/pulp-platform/fpnew/src/fpnew_noncomp.sv
- vendor/pulp-platform/fpnew/src/fpnew_cast_multi.sv
- vendor/pulp-platform/fpnew/src/fpnew_opgroup_block.sv
- vendor/pulp-platform/fpnew/src/fpnew_rounding.sv
- vendor/pulp-platform/fpnew/src/fpnew_top.sv
- vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
- vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
- vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
- vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
- vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
- vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
- vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_mvp_wrapper.sv
- core/frontend/frontend.sv
- core/frontend/instr_scan.sv
- core/frontend/instr_queue.sv
@ -143,16 +143,16 @@ sources:
- corev_apu/riscv-dbg/debug_rom/debug_rom.sv
- corev_apu/register_interface/src/apb_to_reg.sv
- corev_apu/axi/src/axi_multicut.sv
- common/submodules/common_cells/src/cf_math_pkg.sv
- common/submodules/common_cells/src/deprecated/generic_fifo.sv
- common/submodules/common_cells/src/deprecated/pulp_sync.sv
- common/submodules/common_cells/src/deprecated/find_first_one.sv
- common/submodules/common_cells/src/rstgen_bypass.sv
- common/submodules/common_cells/src/rstgen.sv
- common/submodules/common_cells/src/stream_mux.sv
- common/submodules/common_cells/src/stream_demux.sv
- common/submodules/common_cells/src/stream_arbiter.sv
- common/submodules/common_cells/src/stream_arbiter_flushable.sv
- vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
- vendor/pulp-platform/common_cells/src/deprecated/generic_fifo.sv
- vendor/pulp-platform/common_cells/src/deprecated/pulp_sync.sv
- vendor/pulp-platform/common_cells/src/deprecated/find_first_one.sv
- vendor/pulp-platform/common_cells/src/rstgen_bypass.sv
- vendor/pulp-platform/common_cells/src/rstgen.sv
- vendor/pulp-platform/common_cells/src/stream_mux.sv
- vendor/pulp-platform/common_cells/src/stream_demux.sv
- vendor/pulp-platform/common_cells/src/stream_arbiter.sv
- vendor/pulp-platform/common_cells/src/stream_arbiter_flushable.sv
- corev_apu/axi/src/axi_cut.sv
- corev_apu/axi/src/axi_join.sv
- corev_apu/axi/src/axi_delayer.sv
@ -164,28 +164,28 @@ sources:
- corev_apu/axi/src/axi_demux.sv
- corev_apu/axi/src/axi_xbar.sv
- common/local/techlib/fpga/rtl/SyncSpRamBeNx64.sv
- common/submodules/common_cells/src/sync.sv
- common/submodules/common_cells/src/popcount.sv
- common/submodules/common_cells/src/unread.sv
- common/submodules/common_cells/src/cdc_2phase.sv
- common/submodules/common_cells/src/spill_register_flushable.sv
- common/submodules/common_cells/src/spill_register.sv
- common/submodules/common_cells/src/edge_detect.sv
- common/submodules/common_cells/src/fifo_v3.sv
- common/submodules/common_cells/src/deprecated/fifo_v2.sv
- common/submodules/common_cells/src/deprecated/fifo_v1.sv
- common/submodules/common_cells/src/lzc.sv
- common/submodules/common_cells/src/rr_arb_tree.sv
- common/submodules/common_cells/src/deprecated/rrarbiter.sv
- common/submodules/common_cells/src/stream_delay.sv
- common/submodules/common_cells/src/lfsr.sv
- common/submodules/common_cells/src/lfsr_8bit.sv
- common/submodules/common_cells/src/lfsr_16bit.sv
- common/submodules/common_cells/src/counter.sv
- common/submodules/common_cells/src/shift_reg.sv
- common/submodules/common_cells/src/exp_backoff.sv
- common/submodules/common_cells/src/addr_decode.sv
- common/submodules/common_cells/src/stream_register.sv
- vendor/pulp-platform/common_cells/src/sync.sv
- vendor/pulp-platform/common_cells/src/popcount.sv
- vendor/pulp-platform/common_cells/src/unread.sv
- vendor/pulp-platform/common_cells/src/cdc_2phase.sv
- vendor/pulp-platform/common_cells/src/spill_register_flushable.sv
- vendor/pulp-platform/common_cells/src/spill_register.sv
- vendor/pulp-platform/common_cells/src/edge_detect.sv
- vendor/pulp-platform/common_cells/src/fifo_v3.sv
- vendor/pulp-platform/common_cells/src/deprecated/fifo_v2.sv
- vendor/pulp-platform/common_cells/src/deprecated/fifo_v1.sv
- vendor/pulp-platform/common_cells/src/lzc.sv
- vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
- vendor/pulp-platform/common_cells/src/deprecated/rrarbiter.sv
- vendor/pulp-platform/common_cells/src/stream_delay.sv
- vendor/pulp-platform/common_cells/src/lfsr.sv
- vendor/pulp-platform/common_cells/src/lfsr_8bit.sv
- vendor/pulp-platform/common_cells/src/lfsr_16bit.sv
- vendor/pulp-platform/common_cells/src/counter.sv
- vendor/pulp-platform/common_cells/src/shift_reg.sv
- vendor/pulp-platform/common_cells/src/exp_backoff.sv
- vendor/pulp-platform/common_cells/src/addr_decode.sv
- vendor/pulp-platform/common_cells/src/stream_register.sv
- corev_apu/src/tech_cells_generic/src/cluster_clock_inverter.sv
- corev_apu/src/tech_cells_generic/src/pulp_clock_mux2.sv
- target: not(cv32a6)

View file

@ -15,7 +15,7 @@
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
// Date: 15.08.2018
// Description: File list for OpenPiton flow
+incdir+common/submodules/common_cells/include/
+incdir+vendor/pulp-platform/common_cells/include/
+incdir+common/local/util/
+incdir+corev_apu/register_interface/include/
@ -28,27 +28,27 @@ corev_apu/axi/src/axi_pkg.sv
core/include/ariane_axi_pkg.sv
core/include/wt_cache_pkg.sv
core/include/axi_intf.sv
core/fpu/src/fpnew_pkg.sv
vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
core/include/cvxif_pkg.sv
common/submodules/common_cells/src/cf_math_pkg.sv
vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
core/include/instr_tracer_pkg.sv
core/cvxif_example/include/cvxif_instr_pkg.sv
corev_apu/rv_plic/rtl/rv_plic_reg_pkg.sv
common/local/util/sram.sv
common/submodules/common_cells/src/deprecated/rrarbiter.sv
common/submodules/common_cells/src/deprecated/fifo_v1.sv
common/submodules/common_cells/src/deprecated/fifo_v2.sv
common/submodules/common_cells/src/fifo_v3.sv
common/submodules/common_cells/src/shift_reg.sv
common/submodules/common_cells/src/lfsr_8bit.sv
common/submodules/common_cells/src/lfsr.sv
common/submodules/common_cells/src/lzc.sv
common/submodules/common_cells/src/exp_backoff.sv
common/submodules/common_cells/src/rr_arb_tree.sv
common/submodules/common_cells/src/rstgen_bypass.sv
common/submodules/common_cells/src/cdc_2phase.sv
common/submodules/common_cells/src/unread.sv
common/submodules/common_cells/src/popcount.sv
vendor/pulp-platform/common_cells/src/deprecated/rrarbiter.sv
vendor/pulp-platform/common_cells/src/deprecated/fifo_v1.sv
vendor/pulp-platform/common_cells/src/deprecated/fifo_v2.sv
vendor/pulp-platform/common_cells/src/fifo_v3.sv
vendor/pulp-platform/common_cells/src/shift_reg.sv
vendor/pulp-platform/common_cells/src/lfsr_8bit.sv
vendor/pulp-platform/common_cells/src/lfsr.sv
vendor/pulp-platform/common_cells/src/lzc.sv
vendor/pulp-platform/common_cells/src/exp_backoff.sv
vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
vendor/pulp-platform/common_cells/src/rstgen_bypass.sv
vendor/pulp-platform/common_cells/src/cdc_2phase.sv
vendor/pulp-platform/common_cells/src/unread.sv
vendor/pulp-platform/common_cells/src/popcount.sv
corev_apu/axi_mem_if/src/axi2mem.sv
corev_apu/src/tech_cells_generic/src/deprecated/cluster_clk_cells.sv
corev_apu/src/tech_cells_generic/src/deprecated/pulp_clk_cells.sv
@ -132,31 +132,31 @@ corev_apu/fpga/src/axi_slice/src/axi_r_buffer.sv
corev_apu/fpga/src/axi_slice/src/axi_aw_buffer.sv
corev_apu/register_interface/src/apb_to_reg.sv
corev_apu/register_interface/src/reg_intf.sv
core/fpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
core/fpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_mvp_wrapper.sv
core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
core/fpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
core/fpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
core/fpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
core/fpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
core/fpu/src/fpnew_cast_multi.sv
core/fpu/src/fpnew_classifier.sv
core/fpu/src/fpnew_divsqrt_multi.sv
core/fpu/src/fpnew_fma_multi.sv
core/fpu/src/fpnew_fma.sv
core/fpu/src/fpnew_noncomp.sv
core/fpu/src/fpnew_opgroup_block.sv
core/fpu/src/fpnew_opgroup_fmt_slice.sv
core/fpu/src/fpnew_opgroup_multifmt_slice.sv
core/fpu/src/fpnew_rounding.sv
core/fpu/src/fpnew_top.sv
vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_mvp_wrapper.sv
vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
vendor/pulp-platform/fpnew/src/fpnew_cast_multi.sv
vendor/pulp-platform/fpnew/src/fpnew_classifier.sv
vendor/pulp-platform/fpnew/src/fpnew_divsqrt_multi.sv
vendor/pulp-platform/fpnew/src/fpnew_fma_multi.sv
vendor/pulp-platform/fpnew/src/fpnew_fma.sv
vendor/pulp-platform/fpnew/src/fpnew_noncomp.sv
vendor/pulp-platform/fpnew/src/fpnew_opgroup_block.sv
vendor/pulp-platform/fpnew/src/fpnew_opgroup_fmt_slice.sv
vendor/pulp-platform/fpnew/src/fpnew_opgroup_multifmt_slice.sv
vendor/pulp-platform/fpnew/src/fpnew_rounding.sv
vendor/pulp-platform/fpnew/src/fpnew_top.sv
core/pmp/src/pmp.sv
core/pmp/src/pmp_entry.sv
common/local/util/instr_tracer.sv
common/local/util/instr_tracer_if.sv
core/cvxif_example/cvxif_example_coprocessor.sv
core/cvxif_example/instr_decoder.sv
common/submodules/common_cells/src/counter.sv
common/submodules/common_cells/src/delta_counter.sv
vendor/pulp-platform/common_cells/src/counter.sv
vendor/pulp-platform/common_cells/src/delta_counter.sv
core/cvxif_fu.sv

View file

@ -169,13 +169,13 @@ src := core/axi_adapter.sv
corev_apu/riscv-dbg/debug_rom/debug_rom.sv \
corev_apu/register_interface/src/apb_to_reg.sv \
corev_apu/axi/src/axi_multicut.sv \
common/submodules/common_cells/src/rstgen_bypass.sv \
common/submodules/common_cells/src/rstgen.sv \
common/submodules/common_cells/src/stream_mux.sv \
common/submodules/common_cells/src/stream_demux.sv \
common/submodules/common_cells/src/exp_backoff.sv \
common/submodules/common_cells/src/addr_decode.sv \
common/submodules/common_cells/src/stream_register.sv \
vendor/pulp-platform/common_cells/src/rstgen_bypass.sv \
vendor/pulp-platform/common_cells/src/rstgen.sv \
vendor/pulp-platform/common_cells/src/stream_mux.sv \
vendor/pulp-platform/common_cells/src/stream_demux.sv \
vendor/pulp-platform/common_cells/src/exp_backoff.sv \
vendor/pulp-platform/common_cells/src/addr_decode.sv \
vendor/pulp-platform/common_cells/src/stream_register.sv \
corev_apu/axi/src/axi_cut.sv \
corev_apu/axi/src/axi_join.sv \
corev_apu/axi/src/axi_delayer.sv \
@ -186,15 +186,15 @@ src := core/axi_adapter.sv
corev_apu/axi/src/axi_mux.sv \
corev_apu/axi/src/axi_demux.sv \
corev_apu/axi/src/axi_xbar.sv \
common/submodules/common_cells/src/cdc_2phase.sv \
common/submodules/common_cells/src/spill_register_flushable.sv \
common/submodules/common_cells/src/spill_register.sv \
common/submodules/common_cells/src/stream_arbiter.sv \
common/submodules/common_cells/src/stream_arbiter_flushable.sv \
common/submodules/common_cells/src/deprecated/fifo_v1.sv \
common/submodules/common_cells/src/deprecated/fifo_v2.sv \
common/submodules/common_cells/src/stream_delay.sv \
common/submodules/common_cells/src/lfsr_16bit.sv \
vendor/pulp-platform/common_cells/src/cdc_2phase.sv \
vendor/pulp-platform/common_cells/src/spill_register_flushable.sv \
vendor/pulp-platform/common_cells/src/spill_register.sv \
vendor/pulp-platform/common_cells/src/stream_arbiter.sv \
vendor/pulp-platform/common_cells/src/stream_arbiter_flushable.sv \
vendor/pulp-platform/common_cells/src/deprecated/fifo_v1.sv \
vendor/pulp-platform/common_cells/src/deprecated/fifo_v2.sv \
vendor/pulp-platform/common_cells/src/stream_delay.sv \
vendor/pulp-platform/common_cells/src/lfsr_16bit.sv \
corev_apu/src/tech_cells_generic/src/deprecated/cluster_clk_cells.sv \
corev_apu/src/tech_cells_generic/src/deprecated/pulp_clk_cells.sv \
corev_apu/src/tech_cells_generic/src/rtl/tc_clk.sv \
@ -244,7 +244,7 @@ riscv-fp-tests := $(shell xargs printf '\n%s' < $(riscv-fp-tests-list
riscv-benchmarks := $(shell xargs printf '\n%s' < $(riscv-benchmarks-list) | cut -b 1-)
# Search here for include files (e.g.: non-standalone components)
incdir := common/submodules/common_cells/include/ corev_apu/axi/include/ corev_apu/register_interface/include/
incdir := vendor/pulp-platform/common_cells/include/ corev_apu/axi/include/ corev_apu/register_interface/include/
# Compile and sim flags
compile_flag += +cover=bcfst+/dut -incr -64 -nologo -quiet -suppress 13262 -permissive +define+$(defines)
@ -293,7 +293,7 @@ vcs_build: $(dpi-library)/ariane_dpi.so
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog +define+$(defines) -f ../core/Flist.$(target) &&\
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog +define+$(defines) $(filter %.sv,$(ariane_pkg)) +incdir+core/include/+$(VCS_HOME)/etc/uvm-1.2/dpi &&\
vhdlan $(if $(VERDI), -kdb,) -full64 -nc $(filter %.vhd,$(uart_src)) &&\
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -assert svaext +define+$(defines) $(filter %.sv,$(src)) +incdir+../common/submodules/common_cells/include/+../corev_apu/axi/include/+../corev_apu/register_interface/include/ &&\
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -assert svaext +define+$(defines) $(filter %.sv,$(src)) +incdir+../vendor/pulp-platform/common_cells/include/+../corev_apu/axi/include/+../corev_apu/register_interface/include/ &&\
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -ntb_opts uvm-1.2 &&\
vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -ntb_opts uvm-1.2 $(tbs) +define+$(defines) +incdir+../corev_apu/axi/include/ &&\
vcs $(if $(VERDI), -kdb -debug_access+all -lca,) -full64 -timescale=1ns/1ns -ntb_opts uvm-1.2 work.ariane_tb

View file

@ -27,8 +27,8 @@
+define+WT_DCACHE
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/include/
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/src/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/
+incdir+${CVA6_REPO_DIR}/common/local/util/
${CVA6_REPO_DIR}/core/include/cv32a60x_config_pkg.sv
@ -58,40 +58,40 @@ ${CVA6_REPO_DIR}/core/cvxif_example/cvxif_example_coprocessor.sv
${CVA6_REPO_DIR}/core/cvxif_example/instr_decoder.sv
// Common Cells
${CVA6_REPO_DIR}/common/submodules/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/unread.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/exp_backoff.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/unread.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/exp_backoff.sv
// Common Cells for example coprocessor
${CVA6_REPO_DIR}/common/submodules/common_cells/src/counter.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/delta_counter.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/counter.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/delta_counter.sv
// Floating point unit
${CVA6_REPO_DIR}/core/fpu/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_top.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_top.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
// Top-level source files (not necessarily instantiated at the top of the cva6).
${CVA6_REPO_DIR}/core/ariane.sv

View file

@ -27,8 +27,8 @@
+define+WT_DCACHE
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/include/
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/src/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/
+incdir+${CVA6_REPO_DIR}/common/local/util/
${CVA6_REPO_DIR}/core/include/cv32a6_imac_sv0_config_pkg.sv
@ -55,36 +55,36 @@ ${CVA6_REPO_DIR}/core/include/cvxif_pkg.sv
${CVA6_REPO_DIR}/core/cvxif_fu.sv
// Common Cells
${CVA6_REPO_DIR}/common/submodules/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/unread.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/exp_backoff.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/unread.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/exp_backoff.sv
// Floating point unit
${CVA6_REPO_DIR}/core/fpu/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_top.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_top.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
// Top-level source files (not necessarily instantiated at the top of the cva6).
${CVA6_REPO_DIR}/core/ariane.sv

View file

@ -27,8 +27,8 @@
+define+WT_DCACHE
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/include/
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/src/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/
+incdir+${CVA6_REPO_DIR}/common/local/util/
${CVA6_REPO_DIR}/core/include/cv32a6_imac_sv0_config_pkg.sv
@ -55,36 +55,36 @@ ${CVA6_REPO_DIR}/core/include/cvxif_pkg.sv
${CVA6_REPO_DIR}/core/cvxif_fu.sv
// Common Cells
${CVA6_REPO_DIR}/common/submodules/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/unread.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/exp_backoff.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/unread.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/exp_backoff.sv
// Floating point unit
${CVA6_REPO_DIR}/core/fpu/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_top.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_top.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
// Top-level source files (not necessarily instantiated at the top of the cva6).
${CVA6_REPO_DIR}/core/ariane.sv

View file

@ -27,8 +27,8 @@
+define+WT_DCACHE
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/include/
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/src/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/
+incdir+${CVA6_REPO_DIR}/common/local/util/
${CVA6_REPO_DIR}/core/include/cv32a6_imac_sv0_config_pkg.sv
@ -55,36 +55,36 @@ ${CVA6_REPO_DIR}/core/include/cvxif_pkg.sv
${CVA6_REPO_DIR}/core/cvxif_fu.sv
// Common Cells
${CVA6_REPO_DIR}/common/submodules/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/unread.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/exp_backoff.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/unread.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/exp_backoff.sv
// Floating point unit
${CVA6_REPO_DIR}/core/fpu/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_top.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_top.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
// Top-level source files (not necessarily instantiated at the top of the cva6).
${CVA6_REPO_DIR}/core/ariane.sv

View file

@ -27,8 +27,8 @@
+define+WT_DCACHE
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/include/
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/src/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/
+incdir+${CVA6_REPO_DIR}/common/local/util/
${CVA6_REPO_DIR}/core/include/cv32a6_imac_sv0_config_pkg.sv
@ -55,36 +55,36 @@ ${CVA6_REPO_DIR}/core/include/cvxif_pkg.sv
${CVA6_REPO_DIR}/core/cvxif_fu.sv
// Common Cells
${CVA6_REPO_DIR}/common/submodules/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/unread.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/exp_backoff.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/unread.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/exp_backoff.sv
// Floating point unit
${CVA6_REPO_DIR}/core/fpu/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_top.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_top.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
// Top-level source files (not necessarily instantiated at the top of the cva6).
${CVA6_REPO_DIR}/core/ariane.sv

View file

@ -27,8 +27,8 @@
+define+WT_DCACHE
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/include/
+incdir+${CVA6_REPO_DIR}/common/submodules/common_cells/src/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/include/
+incdir+${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/
+incdir+${CVA6_REPO_DIR}/common/local/util/
${CVA6_REPO_DIR}/core/include/cv64a6_imafdc_sv39_config_pkg.sv
@ -58,40 +58,40 @@ ${CVA6_REPO_DIR}/core/cvxif_example/cvxif_example_coprocessor.sv
${CVA6_REPO_DIR}/core/cvxif_example/instr_decoder.sv
// Common Cells
${CVA6_REPO_DIR}/common/submodules/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/unread.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/exp_backoff.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/fifo_v3.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lfsr.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/lzc.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/shift_reg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/unread.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/popcount.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/exp_backoff.sv
// Common Cells for example coprocessor
${CVA6_REPO_DIR}/common/submodules/common_cells/src/counter.sv
${CVA6_REPO_DIR}/common/submodules/common_cells/src/delta_counter.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/counter.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/common_cells/src/delta_counter.sv
// Floating point unit
${CVA6_REPO_DIR}/core/fpu/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_fma.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/core/fpu/src/fpnew_top.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/core/fpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_fma.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpnew_top.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/vendor/pulp-platform/fpnew/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
// Top-level source files (not necessarily instantiated at the top of the cva6).
${CVA6_REPO_DIR}/core/ariane.sv

View file

@ -38,24 +38,24 @@ read_ip { \
}
# read_ip xilinx/xlnx_protocol_checker/ip/xlnx_protocol_checker.xci
set_property include_dirs { "src/axi_sd_bridge/include" "../../common/submodules/common_cells/include" "../axi/include" "../register_interface/include"} [current_fileset]
set_property include_dirs { "src/axi_sd_bridge/include" "../../vendor/pulp-platform/common_cells/include" "../axi/include" "../register_interface/include"} [current_fileset]
source scripts/add_sources.tcl
set_property top ${project}_xilinx [current_fileset]
if {$::env(BOARD) eq "genesys2"} {
read_verilog -sv {src/genesysii.svh ../../common/submodules/common_cells/include/common_cells/registers.svh}
read_verilog -sv {src/genesysii.svh ../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh}
set file "src/genesysii.svh"
set registers "../../common/submodules/common_cells/include/common_cells/registers.svh"
set registers "../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh"
} elseif {$::env(BOARD) eq "kc705"} {
read_verilog -sv {src/kc705.svh ../../common/submodules/common_cells/include/common_cells/registers.svh}
read_verilog -sv {src/kc705.svh ../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh}
set file "src/kc705.svh"
set registers "../../common/submodules/common_cells/include/common_cells/registers.svh"
set registers "../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh"
} elseif {$::env(BOARD) eq "vc707"} {
read_verilog -sv {src/vc707.svh ../../common/submodules/common_cells/include/common_cells/registers.svh}
read_verilog -sv {src/vc707.svh ../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh}
set file "src/vc707.svh"
set registers "../../common/submodules/common_cells/include/common_cells/registers.svh"
set registers "../../vendor/pulp-platform/common_cells/include/common_cells/registers.svh"
} else {
exit 1
}

View file

@ -3,12 +3,12 @@
../../riscv-dbg/src/dm_pkg.sv
../../../core/include/ariane_pkg.sv
../../../core/include/wt_cache_pkg.sv
../../../common/submodules/common_cells/src/cf_math_pkg.sv
../../../vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
../../../common/local/techlib/fpga/rtl/SyncSpRamBeNx64.sv
../../../core/cache_subsystem/cva6_icache.sv
../../../common/submodules/common_cells/src/lfsr.sv
../../../common/submodules/common_cells/src/fifo_v3.sv
../../../common/submodules/common_cells/src/lzc.sv
../../../vendor/pulp-platform/common_cells/src/lfsr.sv
../../../vendor/pulp-platform/common_cells/src/fifo_v3.sv
../../../vendor/pulp-platform/common_cells/src/lzc.sv
../../../common/local/util/sram.sv
hdl/mem_emul.sv
hdl/tlb_emul.sv

View file

@ -23,16 +23,16 @@
../../../core/cache_subsystem/std_nbdcache.sv
../../../core/cache_subsystem/amo_alu.sv
../../../core/cache_subsystem/tag_cmp.sv
../../../common/submodules/common_cells/src/cf_math_pkg.sv
../../../common/submodules/common_cells/src/lfsr_8bit.sv
../../../common/submodules/common_cells/src/fifo_v3.sv
../../../common/submodules/common_cells/src/lzc.sv
../../../common/submodules/common_cells/src/rr_arb_tree.sv
../../../common/submodules/common_cells/src/exp_backoff.sv
../../../common/submodules/common_cells/src/stream_arbiter.sv
../../../common/submodules/common_cells/src/stream_arbiter_flushable.sv
../../../common/submodules/common_cells/src/stream_mux.sv
../../../common/submodules/common_cells/src/stream_demux.sv
../../../vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
../../../vendor/pulp-platform/common_cells/src/lfsr_8bit.sv
../../../vendor/pulp-platform/common_cells/src/fifo_v3.sv
../../../vendor/pulp-platform/common_cells/src/lzc.sv
../../../vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
../../../vendor/pulp-platform/common_cells/src/exp_backoff.sv
../../../vendor/pulp-platform/common_cells/src/stream_arbiter.sv
../../../vendor/pulp-platform/common_cells/src/stream_arbiter_flushable.sv
../../../vendor/pulp-platform/common_cells/src/stream_mux.sv
../../../vendor/pulp-platform/common_cells/src/stream_demux.sv
../../../core/axi_adapter.sv
../../../common/local/util/sram.sv
../../src/axi_riscv_atomics/src/axi_res_tbl.sv

View file

@ -12,7 +12,7 @@
../../axi/src/axi_pkg.sv
../../axi/src/axi_intf.sv
../../axi/src/axi_test.sv
../../../core/fpu/src/fpnew_pkg.sv
../../../vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
../../../core/include/ariane_pkg.sv
../ariane_soc_pkg.sv
../ariane_axi_soc_pkg.sv
@ -28,15 +28,15 @@
../../../core/axi_shim.sv
../../../core/cache_subsystem/wt_axi_adapter.sv
../../../core/cache_subsystem/wt_cache_subsystem.sv
../../../common/submodules/common_cells/src/cf_math_pkg.sv
../../../common/submodules/common_cells/src/lfsr.sv
../../../common/submodules/common_cells/src/fifo_v3.sv
../../../common/submodules/common_cells/src/lzc.sv
../../../common/submodules/common_cells/src/rr_arb_tree.sv
../../../common/submodules/common_cells/src/exp_backoff.sv
../../../common/submodules/common_cells/src/stream_arbiter.sv
../../../common/submodules/common_cells/src/stream_arbiter_flushable.sv
../../../common/submodules/common_cells/src/stream_mux.sv
../../../vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
../../../vendor/pulp-platform/common_cells/src/lfsr.sv
../../../vendor/pulp-platform/common_cells/src/fifo_v3.sv
../../../vendor/pulp-platform/common_cells/src/lzc.sv
../../../vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
../../../vendor/pulp-platform/common_cells/src/exp_backoff.sv
../../../vendor/pulp-platform/common_cells/src/stream_arbiter.sv
../../../vendor/pulp-platform/common_cells/src/stream_arbiter_flushable.sv
../../../vendor/pulp-platform/common_cells/src/stream_mux.sv
../../src/tech_cells_generic/src/rtl/tc_sram.sv
../../../common/local/util/tc_sram_wrapper.sv
../../../common/local/util/sram.sv

View file

@ -16,12 +16,12 @@
../../../core/cache_subsystem/wt_dcache_missunit.sv
../../../core/cache_subsystem/wt_dcache_wbuffer.sv
../../../core/cache_subsystem/wt_dcache.sv
../../../common/submodules/common_cells/src/cf_math_pkg.sv
../../../common/submodules/common_cells/src/lfsr.sv
../../../common/submodules/common_cells/src/fifo_v3.sv
../../../common/submodules/common_cells/src/lzc.sv
../../../common/submodules/common_cells/src/rr_arb_tree.sv
../../../common/submodules/common_cells/src/exp_backoff.sv
../../../vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
../../../vendor/pulp-platform/common_cells/src/lfsr.sv
../../../vendor/pulp-platform/common_cells/src/fifo_v3.sv
../../../vendor/pulp-platform/common_cells/src/lzc.sv
../../../vendor/pulp-platform/common_cells/src/rr_arb_tree.sv
../../../vendor/pulp-platform/common_cells/src/exp_backoff.sv
../../src/tech_cells_generic/src/rtl/tc_sram.sv
../../../common/local/util/tc_sram_wrapper.sv
../../../common/local/util/sram.sv

View file

@ -17,7 +17,7 @@ set clk_period $PERIOD
set input_delay $INPUT_DELAY
set output_delay $OUTPUT_DELAY
set_app_var search_path "../../core/fpu/src/common_cells/include/ $search_path"
set_app_var search_path "../../vendor/pulp-platform/fpnew/src/common_cells/include/ $search_path"
sh rm -rf work
sh mkdir work

5
util/README.md Normal file
View file

@ -0,0 +1,5 @@
Content:
* vendor.py
- vendorization script
- copied from https://github.com/openhwgroup/cv32e40p/blob/master/util/vendor.py, commit 69e839e

782
util/vendor.py Normal file
View file

@ -0,0 +1,782 @@
#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
'''A tool to copy source code from upstream into this repository.
For an introduction to using this tool, see doc/ug/vendor_hw.md in this
repository (on the internet at https://docs.opentitan.org/doc/ug/vendor_hw/).
For full documentation, see doc/rm/vendor_in_tool.md (on the internet at
https://docs.opentitan.org/doc/rm/vendor_in_tool).
'''
import argparse
import fnmatch
import logging as log
import os
import re
import shutil
import subprocess
import sys
import tempfile
import textwrap
from pathlib import Path
import hjson
EXCLUDE_ALWAYS = ['.git']
LOCK_FILE_HEADER = """// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// This file is generated by the util/vendor script. Please do not modify it
// manually.
"""
# Keys in the description (configuration) file which can be overridden through
# the command line.
OVERRIDABLE_DESC_KEYS = [
'patch_repo.url',
'patch_repo.rev_base',
'patch_repo.rev_patched',
'upstream.url',
'upstream.ref',
]
verbose = False
def git_is_clean_workdir(git_workdir):
"""Check if the git working directory is clean (no unstaged or staged changes)"""
cmd = ['git', 'status', '--untracked-files=no', '--porcelain']
modified_files = subprocess.run(cmd,
cwd=str(git_workdir),
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).stdout.strip()
return not modified_files
def github_qualify_references(log, repo_userorg, repo_name):
""" Replace "unqualified" GitHub references with "fully qualified" one
GitHub automatically links issues and pull requests if they have a specific
format. Links can be qualified with the user/org name and the repository
name, or unqualified, if they only contain the issue or pull request number.
This function converts all unqualified references to qualified ones.
See https://help.github.com/en/articles/autolinked-references-and-urls#issues-and-pull-requests
for a documentation of all supported formats.
"""
r = re.compile(r"(^|[^\w])(?:#|[gG][hH]-)(\d+)\b")
repl_str = r'\1%s/%s#\2' % (repo_userorg, repo_name)
return [r.sub(repl_str, l) for l in log]
def test_github_qualify_references():
repo_userorg = 'lowRISC'
repo_name = 'ibex'
# Unqualified references, should be replaced
items_unqualified = [
'#28',
'GH-27',
'klaus #27',
'Fixes #27',
'Fixes #27 and #28',
'(#27)',
'something (#27) done',
'#27 and (GH-38)',
]
exp_items_unqualified = [
'lowRISC/ibex#28',
'lowRISC/ibex#27',
'klaus lowRISC/ibex#27',
'Fixes lowRISC/ibex#27',
'Fixes lowRISC/ibex#27 and lowRISC/ibex#28',
'(lowRISC/ibex#27)',
'something (lowRISC/ibex#27) done',
'lowRISC/ibex#27 and (lowRISC/ibex#38)',
]
assert github_qualify_references(items_unqualified, repo_userorg,
repo_name) == exp_items_unqualified
# Qualified references, should stay as they are
items_qualified = [
'Fixes lowrisc/ibex#27',
'lowrisc/ibex#2',
]
assert github_qualify_references(items_qualified, repo_userorg,
repo_name) == items_qualified
# Invalid references, should stay as they are
items_invalid = [
'something#27',
'lowrisc/ibex#',
]
assert github_qualify_references(items_invalid, repo_userorg,
repo_name) == items_invalid
def test_github_parse_url():
assert github_parse_url('https://example.com/something/asdf.git') is None
assert github_parse_url('https://github.com/lowRISC/ibex.git') == (
'lowRISC', 'ibex')
assert github_parse_url('https://github.com/lowRISC/ibex') == ('lowRISC',
'ibex')
assert github_parse_url('git@github.com:lowRISC/ibex.git') == ('lowRISC',
'ibex')
def github_parse_url(github_repo_url):
"""Parse a GitHub repository URL into its parts.
Return a tuple (userorg, name), or None if the parsing failed.
"""
regex = r"(?:@github\.com\:|\/github\.com\/)([a-zA-Z\d-]+)\/([a-zA-Z\d-]+)(?:\.git)?$"
m = re.search(regex, github_repo_url)
if m is None:
return None
return (m.group(1), m.group(2))
def produce_shortlog(clone_dir, mapping, old_rev, new_rev):
""" Produce a list of changes between two revisions, one revision per line
Merges are excluded"""
# If mapping is None, we want to list all changes below clone_dir.
# Otherwise, we want to list changes in each 'source' in the mapping. Since
# these strings are paths relative to clone_dir, we can just pass them all
# to git and let it figure out what to do.
subdirs = (['.'] if mapping is None
else [m.from_path for m in mapping.items])
cmd = (['git', '-C', str(clone_dir), 'log',
'--pretty=format:%s (%aN)', '--no-merges',
old_rev + '..' + new_rev] +
subdirs)
try:
proc = subprocess.run(cmd,
cwd=str(clone_dir),
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
return proc.stdout.splitlines()
except subprocess.CalledProcessError as e:
log.error("Unable to capture shortlog: %s", e.stderr)
return ""
def format_list_to_str(list, width=70):
""" Create Markdown-style formatted string from a list of strings """
wrapper = textwrap.TextWrapper(initial_indent="* ",
subsequent_indent=" ",
width=width)
return '\n'.join([wrapper.fill(s) for s in list])
class JsonError(Exception):
'''An error class for when data in the source HJSON is bad'''
def __init__(self, path, msg):
self.path = path
self.msg = msg
def __str__(self):
return 'In hjson at {}, {}'.format(self.path, self.msg)
def get_field(path, where, data, name, expected_type=dict, optional=False, constructor=None):
value = data.get(name)
if value is None:
if not optional:
raise JsonError(path, '{}, missing {!r} field.'.format(where, name))
return None
if not isinstance(value, expected_type):
raise JsonError(path,
'{}, the {!r} field is {!r}, but should be of type {!r}.'
.format(where, name, value, expected_type.__name__))
return value if constructor is None else constructor(value)
class Upstream:
'''A class representing the 'upstream' field in a config or lock file'''
def __init__(self, path, data):
# Fields: 'url', 'rev', 'only_subdir' (optional). All should be strings.
where = 'in upstream dict'
self.url = get_field(path, where, data, 'url', str)
self.rev = get_field(path, where, data, 'rev', str)
self.only_subdir = get_field(path, where, data,
'only_subdir', str, optional=True)
def as_dict(self):
data = {'url': self.url, 'rev': self.rev}
if self.only_subdir is not None:
data['only_subdir'] = self.only_subdir
return data
class PatchRepo:
'''A class representing the 'patch_repo' field in a config file'''
def __init__(self, path, data):
# Fields: 'url', 'rev_base', 'rev_patched'. All should be strings.
where = 'in patch_repo dict'
self.url = get_field(path, where, data, 'url', str)
self.rev_base = get_field(path, where, data, 'rev_base', str)
self.rev_patched = get_field(path, where, data, 'rev_patched', str)
class Mapping1:
'''A class to represent a single item in the 'mapping' field in a config file'''
def __init__(self, from_path, to_path, patch_dir):
self.from_path = from_path
self.to_path = to_path
self.patch_dir = patch_dir
@staticmethod
def make(path, idx, data):
assert isinstance(data, dict)
def get_path(name, optional=False):
val = get_field(path, 'in mapping entry {}'.format(idx + 1),
data, name, expected_type=str, optional=optional)
if val is None:
return None
# Check that the paths aren't evil ('../../../foo' or '/etc/passwd'
# are *not* ok!)
val = os.path.normpath(val)
if val.startswith('/') or val.startswith('..'):
raise JsonError(path,
'Mapping entry {} has a bad path for {!r} '
'(must be a relative path that doesn\'t '
'escape the directory)'
.format(idx + 1, name))
return Path(val)
from_path = get_path('from')
to_path = get_path('to')
patch_dir = get_path('patch_dir', optional=True)
return Mapping1(from_path, to_path, patch_dir)
@staticmethod
def make_default(have_patch_dir):
'''Make a default mapping1, which copies everything straight through'''
return Mapping1(Path('.'), Path('.'),
Path('.') if have_patch_dir else None)
@staticmethod
def apply_patch(basedir, patchfile):
cmd = ['git', 'apply', '--directory', str(basedir), '-p1',
str(patchfile)]
if verbose:
cmd += ['--verbose']
subprocess.run(cmd, check=True)
def import_from_upstream(self, upstream_path,
target_path, exclude_files, patch_dir):
'''Copy from the upstream checkout to target_path'''
from_path = upstream_path / self.from_path
to_path = target_path / self.to_path
# Make sure the target directory actually exists
to_path.parent.mkdir(exist_ok=True, parents=True)
# Copy src to dst recursively. For directories, we can use
# shutil.copytree. This doesn't support files, though, so we have to
# check for them first.
if from_path.is_file():
shutil.copy(str(from_path), str(to_path))
else:
ignore = ignore_patterns(str(upstream_path), *exclude_files)
shutil.copytree(str(from_path), str(to_path), ignore=ignore)
# Apply any patches to the copied files. If self.patch_dir is None,
# there are none to apply. Otherwise, resolve it relative to patch_dir.
if self.patch_dir is not None:
patches = (patch_dir / self.patch_dir).glob('*.patch')
for patch in sorted(patches):
log.info("Applying patch {} at {}".format(patch, to_path))
Mapping1.apply_patch(to_path, patch)
class Mapping:
'''A class representing the 'mapping' field in a config file
This should be a list of dicts.
'''
def __init__(self, items):
self.items = items
@staticmethod
def make(path, data):
items = []
assert isinstance(data, list)
for idx, elt in enumerate(data):
if not isinstance(elt, dict):
raise JsonError(path, 'Mapping element {!r} is not a dict.'.format(elt))
items.append(Mapping1.make(path, idx, elt))
return Mapping(items)
def has_patch_dir(self):
'''Check whether at least one item defines a patch dir'''
for item in self.items:
if item.patch_dir is not None:
return True
return False
class LockDesc:
'''A class representing the contents of a lock file'''
def __init__(self, handle):
data = hjson.loads(handle.read(), use_decimal=True)
self.upstream = get_field(handle.name, 'at top-level', data, 'upstream',
constructor=lambda data: Upstream(handle.name, data))
class Desc:
'''A class representing the configuration file'''
def __init__(self, handle, desc_overrides):
# Ensure description file matches our naming rules (otherwise we don't
# know the name for the lockfile). This regex checks that we have the
# right suffix and a nonempty name.
if not re.match(r'.+\.vendor\.hjson', handle.name):
raise ValueError("Description file names must have a .vendor.hjson suffix.")
data = hjson.loads(handle.read(), use_decimal=True)
where = 'at top-level'
self.apply_overrides(data, desc_overrides)
path = Path(handle.name)
def take_path(p):
return path.parent / p
self.path = path
self.name = get_field(path, where, data, 'name', expected_type=str)
self.target_dir = get_field(path, where, data, 'target_dir',
expected_type=str, constructor=take_path)
self.upstream = get_field(path, where, data, 'upstream',
constructor=lambda data: Upstream(path, data))
self.patch_dir = get_field(path, where, data, 'patch_dir',
optional=True, expected_type=str, constructor=take_path)
self.patch_repo = get_field(path, where, data, 'patch_repo',
optional=True,
constructor=lambda data: PatchRepo(path, data))
self.exclude_from_upstream = (get_field(path, where, data, 'exclude_from_upstream',
optional=True, expected_type=list) or
[])
self.mapping = get_field(path, where, data, 'mapping', optional=True,
expected_type=list,
constructor=lambda data: Mapping.make(path, data))
# Add default exclusions
self.exclude_from_upstream += EXCLUDE_ALWAYS
# It doesn't make sense to define a patch_repo, but not a patch_dir
# (where should we put the patches that we get?)
if self.patch_repo is not None and self.patch_dir is None:
raise JsonError(path, 'Has patch_repo but not patch_dir.')
# We don't currently support a patch_repo and a mapping (just because
# we haven't written the code to generate the patches across subdirs
# yet). Tracked in issue #2317.
if self.patch_repo is not None and self.mapping is not None:
raise JsonError(path,
"vendor.py doesn't currently support patch_repo "
"and mapping at the same time (see issue #2317).")
# If a patch_dir is defined and there is no mapping, we will look in
# that directory for patches and apply them in (the only) directory
# that we copy stuff into.
#
# If there is a mapping check that there is a patch_dir if and only if
# least one mapping entry uses it.
if self.mapping is not None:
if self.patch_dir is not None:
if not self.mapping.has_patch_dir():
raise JsonError(path, 'Has patch_dir, but no mapping item uses it.')
else:
if self.mapping.has_patch_dir():
raise JsonError(path,
'Has a mapping item with a patch directory, '
'but there is no global patch_dir key.')
# Check that exclude_from_upstream really is a list of strings. Most of
# this type-checking is in the constructors for field types, but we
# don't have a "ExcludeList" class, so have to do it explicitly here.
for efu in self.exclude_from_upstream:
if not isinstance(efu, str):
raise JsonError(path,
'exclude_from_upstream has entry {}, which is not a string.'
.format(efu))
def apply_overrides(self, desc_data, desc_overrides):
""" Apply overrides from command line to configuration file data
Updates are applied to the desc_data reference."""
for key, value in desc_overrides:
log.info("Overriding description key {!r} with value {!r}".format(
key, value))
ref = desc_data
split_keys = key.split('.')
for key_part in split_keys[:-1]:
if key_part not in ref:
ref[key_part] = {}
ref = ref[key_part]
ref[split_keys[-1]] = value
def lock_file_path(self):
desc_file_stem = self.path.name.rsplit('.', 2)[0]
return self.path.with_name(desc_file_stem + '.lock.hjson')
def import_from_upstream(self, upstream_path):
log.info('Copying upstream sources to {}'.format(self.target_dir))
# Remove existing directories before importing them again
shutil.rmtree(str(self.target_dir), ignore_errors=True)
items = (self.mapping.items if self.mapping is not None
else [Mapping1.make_default(self.patch_dir is not None)])
for map1 in items:
map1.import_from_upstream(upstream_path,
self.target_dir,
self.exclude_from_upstream,
self.patch_dir)
def refresh_patches(desc):
if desc.patch_repo is None:
log.fatal('Unable to refresh patches, patch_repo not set in config.')
sys.exit(1)
log.info('Refreshing patches in {}'.format(desc.patch_dir))
# remove existing patches
for patch in desc.patch_dir.glob('*.patch'):
os.unlink(str(patch))
# get current patches
_export_patches(desc.patch_repo.url, desc.patch_dir,
desc.patch_repo.rev_base,
desc.patch_repo.rev_patched)
def _export_patches(patchrepo_clone_url, target_patch_dir, upstream_rev,
patched_rev):
with tempfile.TemporaryDirectory() as clone_dir:
clone_git_repo(patchrepo_clone_url, clone_dir, patched_rev)
rev_range = 'origin/' + upstream_rev + '..' + 'origin/' + patched_rev
cmd = [
'git',
'format-patch',
'--no-signature',
'--no-stat',
'-o',
str(target_patch_dir.resolve()),
rev_range
]
if not verbose:
cmd += ['-q']
subprocess.run(cmd, cwd=str(clone_dir), check=True)
def ignore_patterns(base_dir, *patterns):
"""Similar to shutil.ignore_patterns, but with support for directory excludes."""
def _rel_to_base(path, name):
return os.path.relpath(os.path.join(path, name), base_dir)
def _ignore_patterns(path, names):
ignored_names = []
for pattern in patterns:
pattern_matches = [
n for n in names
if fnmatch.fnmatch(_rel_to_base(path, n), pattern)
]
ignored_names.extend(pattern_matches)
return set(ignored_names)
return _ignore_patterns
def clone_git_repo(repo_url, clone_dir, rev='master'):
log.info('Cloning upstream repository %s @ %s', repo_url, rev)
# Clone the whole repository
cmd = ['git', 'clone', '--no-single-branch']
if not verbose:
cmd += ['-q']
cmd += [repo_url, str(clone_dir)]
subprocess.run(cmd, check=True)
# Check out exactly the revision requested
cmd = ['git', '-C', str(clone_dir), 'checkout', '--force', rev]
if not verbose:
cmd += ['-q']
subprocess.run(cmd, check=True)
# Get revision information
cmd = ['git', '-C', str(clone_dir), 'rev-parse', 'HEAD']
rev = subprocess.run(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
universal_newlines=True).stdout.strip()
log.info('Cloned at revision %s', rev)
return rev
def git_get_short_rev(clone_dir, rev):
""" Get the shortened SHA-1 hash for a revision """
cmd = ['git', '-C', str(clone_dir), 'rev-parse', '--short', rev]
short_rev = subprocess.run(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True,
universal_newlines=True).stdout.strip()
return short_rev
def git_add_commit(paths, commit_msg):
""" Stage and commit all changes in paths"""
assert paths
base_dir = paths[0].parent
# Stage all changes
#
# Rather than figuring out GIT_DIR properly, we cheat and use "git -C" to
# pretend that we're running in base_dir. Of course, the elements of paths
# are relative to our actual working directory. Rather than do anything
# clever, we just resolve them to absolute paths as we go.
abs_paths = [p.resolve() for p in paths]
subprocess.run(['git', '-C', base_dir, 'add'] + abs_paths, check=True)
cmd_commit = ['git', '-C', base_dir, 'commit', '-s', '-F', '-']
try:
subprocess.run(cmd_commit,
check=True,
universal_newlines=True,
input=commit_msg)
except subprocess.CalledProcessError:
log.warning("Unable to create commit. Are there no changes?")
def define_arg_type(arg):
"""Sanity-check and return a config file override argument"""
try:
(key, value) = [v.strip() for v in arg.split('=', 2)]
except Exception:
raise argparse.ArgumentTypeError(
'unable to parse {!r}: configuration overrides must be in the form key=value'
.format(arg))
if key not in OVERRIDABLE_DESC_KEYS:
raise argparse.ArgumentTypeError(
'invalid configuration override: key {!r} cannot be overwritten'
.format(key))
return (key, value)
def main(argv):
parser = argparse.ArgumentParser(prog="vendor", description=__doc__)
parser.add_argument(
'--update',
'-U',
dest='update',
action='store_true',
help='Update locked version of repository with upstream changes')
parser.add_argument('--refresh-patches',
action='store_true',
help='Refresh the patches from the patch repository')
parser.add_argument('--commit',
'-c',
action='store_true',
help='Commit the changes')
parser.add_argument('--desc-override',
'-D',
dest="desc_overrides",
action="append",
type=define_arg_type,
default=[],
help='Override a setting in the description file. '
'Format: -Dsome.key=value. '
'Can be used multiple times.')
parser.add_argument('desc_file',
metavar='file',
type=argparse.FileType('r', encoding='UTF-8'),
help='vendoring description file (*.vendor.hjson)')
parser.add_argument('--verbose', '-v', action='store_true', help='Verbose')
args = parser.parse_args()
global verbose
verbose = args.verbose
if (verbose):
log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
else:
log.basicConfig(format="%(levelname)s: %(message)s")
# Load input files (desc file; lock file) and check syntax etc.
try:
# Load description file
desc = Desc(args.desc_file, args.desc_overrides)
lock_file_path = desc.lock_file_path()
# Try to load lock file (which might not exist)
try:
with open(str(lock_file_path), 'r') as lock_file:
lock = LockDesc(lock_file)
except FileNotFoundError:
lock = None
except (JsonError, ValueError) as err:
log.fatal(str(err))
raise SystemExit(1)
# Check for a clean working directory when commit is requested
if args.commit:
if not git_is_clean_workdir(desc.path.parent):
log.fatal("A clean git working directory is required for "
"--commit/-c. git stash your changes and try again.")
raise SystemExit(1)
if lock is None and not args.update:
log.warning("No lock file at {}, so will update upstream repo."
.format(str(desc.lock_file_path())))
args.update = True
# If we have a lock file and we're not in update mode, override desc's
# upstream field with the one from the lock file. Keep track of whether the
# URL differs (in which case, we can't get a shortlog)
changed_url = False
if lock is not None:
changed_url = desc.upstream.url != lock.upstream.url
if not args.update:
desc.upstream = lock.upstream
if args.refresh_patches:
refresh_patches(desc)
with tempfile.TemporaryDirectory() as clone_dir:
# clone upstream repository
upstream_new_rev = clone_git_repo(desc.upstream.url, clone_dir, rev=desc.upstream.rev)
if not args.update:
if upstream_new_rev != lock.upstream.rev:
log.fatal(
"Revision mismatch. Unable to re-clone locked version of repository."
)
log.fatal("Attempted revision: %s", desc.upstream.rev)
log.fatal("Re-cloned revision: %s", upstream_new_rev)
raise SystemExit(1)
clone_subdir = Path(clone_dir)
if desc.upstream.only_subdir is not None:
clone_subdir = clone_subdir / desc.upstream.only_subdir
if not clone_subdir.is_dir():
log.fatal("subdir '{}' does not exist in repo"
.format(desc.upstream.only_subdir))
raise SystemExit(1)
# copy selected files from upstream repo and apply patches as necessary
desc.import_from_upstream(clone_subdir)
# get shortlog
get_shortlog = args.update
if args.update:
if lock is None:
get_shortlog = False
log.warning("No lock file %s: unable to summarize changes.", str(lock_file_path))
elif changed_url:
get_shortlog = False
log.warning("The repository URL changed since the last run. "
"Unable to get log of changes.")
shortlog = None
if get_shortlog:
shortlog = produce_shortlog(clone_subdir, desc.mapping,
lock.upstream.rev, upstream_new_rev)
# Ensure fully-qualified issue/PR references for GitHub repos
gh_repo_info = github_parse_url(desc.upstream.url)
if gh_repo_info:
shortlog = github_qualify_references(shortlog, gh_repo_info[0],
gh_repo_info[1])
log.info("Changes since the last import:\n" +
format_list_to_str(shortlog))
# write lock file
if args.update:
lock_data = {}
lock_data['upstream'] = desc.upstream.as_dict()
lock_data['upstream']['rev'] = upstream_new_rev
with open(str(lock_file_path), 'w', encoding='UTF-8') as f:
f.write(LOCK_FILE_HEADER)
hjson.dump(lock_data, f)
f.write("\n")
log.info("Wrote lock file %s", str(lock_file_path))
# Commit changes
if args.commit:
sha_short = git_get_short_rev(clone_subdir, upstream_new_rev)
repo_info = github_parse_url(desc.upstream.url)
if repo_info is not None:
sha_short = "%s/%s@%s" % (repo_info[0], repo_info[1],
sha_short)
commit_msg_subject = 'Update %s to %s' % (desc.name, sha_short)
intro = ('Update code from {}upstream repository {} to revision {}'
.format(('' if desc.upstream.only_subdir is None else
'subdir {} in '.format(desc.upstream.only_subdir)),
desc.upstream.url,
upstream_new_rev))
commit_msg_body = textwrap.fill(intro, width=70)
if shortlog:
commit_msg_body += "\n\n"
commit_msg_body += format_list_to_str(shortlog, width=70)
commit_msg = commit_msg_subject + "\n\n" + commit_msg_body
commit_paths = []
commit_paths.append(desc.target_dir)
if args.refresh_patches:
commit_paths.append(desc.patch_dir)
commit_paths.append(lock_file_path)
git_add_commit(commit_paths, commit_msg)
log.info('Import finished')
if __name__ == '__main__':
try:
main(sys.argv)
except subprocess.CalledProcessError as e:
log.fatal("Called program '%s' returned with %d.\n"
"STDOUT:\n%s\n"
"STDERR:\n%s\n" %
(" ".join(e.cmd), e.returncode, e.stdout, e.stderr))
raise
except KeyboardInterrupt:
log.info("Aborting operation on user request.")
sys.exit(1)

View file

@ -0,0 +1,14 @@
.*
!.travis.yml
!.git*
*.out
*~
/Bender.lock
/Bender.local
build
formal/fifo_v3
formal/counter
formal/fall_through_register
*.check
*.vcd
obj_dir/

View file

@ -0,0 +1,342 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## Unreleased
## 1.23.0 - 2021-09-05
### Added
- Add `cc_onehot`
- `isochronous_4phase_handshake`: Isochronous clock domain crossing cutting all paths using a 4-phase handshake.
- Changed `isochronous_spill_register_tb` to `isochronous_crossing_tb` also covering the `isochronous_4phase_handshake`
module.
- Make reset value of `sync` module parameterizable.
### Changed
- `id_queue`: Allow simultaneous input and output requests in `FULL_BW` mode
## 1.22.1 - 2021-06-14
### Fixed
- Remove breaking change of `spill_register`
## 1.22.0 - 2021-06-09
### Added
- Add `spill_register_flushable`
### Changed
- `registers.svh`: Merge explicit and implicit register variants into `` `FF `` and `` `FFL `` macros
- `rr_arb_tree`: Allow flushing locked decision
- Improved `verific` compatibility
## 1.21.0 - 2021-01-28
### Changed
- Remove `timeprecision/timeunit` arguments
- Update `common_verification` to `0.2.0`
- Update `tech_cells_generic` to `0.2.3`
## 1.20.1 - 2021-01-21
### Changed
- `id_queue`: Replace default or reset value of signals that were assigned `'x` with `'0`.
- `id_queue`: Use `cf_math_pkg::idx_width()` for computation of localparams.
### Fixed
- Add `XSIM` define guard for statements incompatible with `xsim`.
## 1.20.0 - 2020-11-04
### Added
- assertions: Assertion include header with macros (from lowrisc)
### Changed
- `sram.sv`: Deprecated as it has been moved to `tech_cells_generic`
### Fixed
- `stream_register`: Fix `DATA_WIDTH` of instantiated FIFO.
- `stream_xbar`: Add missing argument in assertion error string.
- Lint style fixes
- `stream_omega`: Fix parse issue with verible.
- `src_files.yml`: Fix compile order and missing modules.
## 1.19.0 - 2020-05-25
### Added
- stream_to_mem: Allows to use memories with flow control (req/gnt) for requests but
without flow control for output data to be used in streams.
- isochronous_spill_register: Isochronous clock domain crossing cutting all paths.
- `rr_arb_tree_tb`: Systemverilog testbench for `rr_arb_tree`, which checks for fair throughput.
- `cf_math_pkg::idx_width`: Constant function for defining the binary representation width
of an index signal.
### Changed
- `addr_decode`: Use `cf_math_pkg::idx_width` for computing the index width, inline documentation.
- `lzc`: Use `cf_math_pkg::idx_width` for computing the index width, inline documentation.
- `Bender`: Change levels of modules affected by depending on `cf_math_pkg::idx_width()`.
- `stream_xbar`: Fully connected stream bassed interconnect with variable number of inputs and outputs.
- `stream_xbar`: Fully connected stream-bassed interconnect with a variable number of inputs and outputs.
- `stream_omega_net`: Stream-based network implementing an omega topology. Variable number of inputs,
outputs and radix. Topology is isomorphic to a butterfly network.
### Fixed
- Improve tool compatibility.
- `rr_arb_tree`: Properly degenerate `rr_i` and `idx_o` signals.
- `rr_arb_tree`: Add parameter `FairArb` to distribute throughput of input requests evenly when
not all inputs have requests active.
- `stream_demux`: Properly degenerate `inp_sel_i` signal.
## 1.18.0 - 2020-04-15
### Added
- stream_fork_dynamic: Wrapper around `stream_fork` for partial forking.
- stream_join: Join multiple Ready/Valid handshakes to one common handshake.
- SECDED (Single Error Correction, Double Error Detection) encoder and decoder
- SECDED Verilator-based testbench
- Travis build for SECDED module
## 1.17.0 - 2020-04-09
### Added
- stream_fifo: Ready/Valid handshake wrapper around `fifo_v3`
## 1.16.4 - 2020-03-02
### Fixed
- id_queue: Fix generation of `head_tail_q` registers
## 1.16.3 - 2020-02-11
### Fixed
- Handle degenerated `addr_decode` with `NoIndices == 1`, change default parameters to `32'd0`
## 1.16.2 - 2020-02-04
### Fixed
- Fix author section in Bender.yml
## 1.16.1 - 2020-02-03
### Fixed
- `rr_arb_tree`: Add guard SVA statement for Verilator
- Added missing sources in `Bender.yml` and `src_files.yml`
## 1.16.0 - 2020-01-13
### Fixed
- Handle degenerated `onehot_to_bin` with `ONEHOT_WIDTH == 1`
- Handle degenerated `id_queue` with `CAPACITY == 1` or `HT_CAPACITY == 1`
- Fix `cdc_fifo_gray` to be a safe clock domain crossing (CDC)
## 1.15.0 - 2019-12-09
### Added
- Added address map decoder module
### Fixed
- Handle degenerated `lzc` with `WIDTH == 1`
## 1.14.0 - 2019-10-08
### Added
- Added spubstitution-permutation hash function module
- Added couning-bloom-filter module
- `spill_register`: Added Bypass parameter
- `counter`: Added sticky overflow
- Added counter with variable delta
- Added counter that tracks its maximum value
### Changed
- Added formal testbench for `fifo` and `fall_through_regsiter`
## 1.13.1 - 2019-06-01
### Changed
- Fix path in `src_files.yml` for `stream_arbiter` and `stream_arbiter_flushable`
## 1.13.0 - 2019-05-29
### Added
- Added exponential backoff window module
- Added parametric Galois LFSR module with optional whitening feature
- Added `cf_math_pkg`: Constant Function implementations of mathematical functions for HDL elaboration
### Changed
- Parametric payload data type for `rr_arb_tree`
### Deprecated
- The following arbiter implementations are deprecated and superseded by `rr_arb_tree`:
- Priority arbiter `prioarbiter`
- Round-robin arbiter `rrarbiter`
### Fixed
## 1.12.0 - 2019-04-09
### Added
- Add priority arbiter
- Add Pseudo Least Recently Used tree
- Add round robin arbiter mux tree
### Changed
- Add selectable arbiter implementation for `stream_arbiter` and `stream_arbiter_flushable`. One can choose between priority (`prio`) and round-robin arbitration (`rr`).
- Add `$onehot0` assertion in one-hot to bin
- Rework `rrarbiter` unit (uses `rr_arb_tree` implementation underneath)
## 1.11.0 - 2019-03-20
### Added
- Add stream fork
- Add fall-through register
- Add stream filter
- Add ID queue
### Changed
- `sync_wedge` use existing synchronizer. This defines a single place where a tech-specific synchronizer can be defined.
### Fixed
- Fix FIFO push and pop signals in `stream_register` to observe interface prerequisites.
- In `fifo_v3`, fix data output when pushing into empty fall-through FIFO. Previously, the data
output of an empty fall-through FIFO with data at its input (and `push_i=1`) depended on
`pop_i`: When `pop_i=0`, old, invalid data were visible at the output (even though `empty_o=0`,
indicating that the data output is valid). Only when `pop_i=1`, the data from the input fell
through. One consequence of this bug was that `data_o` of the `fall_through_register` could change
while `valid_o=1`, violating the basic stream specification.
## 1.10.0 - 2018-12-18
### Added
- Add `fifo_v3` with generic fill count
- Add 16 bit LFSR
- Add stream delayer
- Add stream arbiter
- Add register macros for RTL
- Add shift register
### Changed
- Make number of registers of `rstgen_bypass` a parameter.
### Fixed
- Fix `valid_i` and `grant_i` guarantees in `generic_fifo` for backward compatibility.
- LZC: Synthesis of streaming operators in ternary operators
- Add missing entry for `popcount` to `Bender.yml`.
- Add default values for parameters to improve compatibility with Synopsys DC and Vivado.
## 1.9.0 - 2018-11-02
### Added
- Add popcount circuit `popcount`
## 1.8.0 - 2018-10-15
### Added
- Add lock feature to the rrarbiter. This prevents the arbiter to change the decision when we have pending requests that remain unaknowledged for several cycles.
- Add deglitching circuit
- Add generic clock divider
- Add edge detecter as alias to sync_wedge (name is more expressive)
- Add generic counter
- Add moving deglitcher
## 1.7.6 - 2018-09-27
### Added
- Add reset synchronizer with explicit reset bypass in testmode
## 1.7.5 - 2018-09-06
### Fixed
- Fix incompatibility with verilator
- Fix dependency to open-source repo
## 1.7.4 - 2018-09-06
- Fix assertions in `fifo_v2` (write on full / read on empty did not trigger properly)
## 1.7.3 - 2018-08-27
### Fixed
- Use proper `fifo_v2` in `generic_fifo` module.
## 1.7.2 - 2018-08-27
### Added
- Almost full/empty flags to FIFO, as `fifo_v2`.
### Changed
- FIFO moved to `fifo_v1` and instantiates `fifo_v2`.
## 1.7.1 - 2018-08-27
### Fixed
- Revert breaking changes to `fifo`.
## 1.7.0 - 2018-08-24
### Added
- Add stream register (`stream_register`).
- Add stream multiplexer and demultiplexer (`stream_mux`, `stream_demux`).
- Add round robin arbiter (`rrarbiter`).
- Add leading zero counter (`lzc`).
### Changed
- Deprecate `find_first_one` in favor of `lzc`.
## 1.6.0 - 2018-04-03
### Added
- Add binary to Gray code converter.
- Add Gray code to binary converter.
- Add Gray code testbench.
- Add CDC FIFO based on Gray counters. This is a faster alternative to the 2-phase FIFO which also works if a domain's clock has stopped.
### Changed
- Rename `cdc_fifo` to `cdc_fifo_2phase`.
- Adjust CDC FIFO testbench to cover both implementations.
## 1.5.4 - 2018-03-31
### Changed
- Replace explicit clock gate in `fifo` with implicit one.
## 1.5.3 - 2018-03-16
### Changed
- Remove duplicate deprecated modules.
## 1.5.2 - 2018-03-16
### Changed
- Remove deprecated `rstgen` and fix interface.
## 1.5.1 - 2018-03-16
### Changed
- Remove deprecated `onehot_to_bin`.
## 1.5.0 - 2018-03-14
### Added
- Add behavioural SRAM model
## 1.4.0 - 2018-03-14
### Added
- Clock domain crossing FIFO
### Changed
- Re-name new sync modules to resolve namespace collisions
## 1.3.0 - 2018-03-12
### Added
- 2-phase clock domain crossing
- Add old common cells as deprecated legacy modules
## 1.2.3 - 2018-03-09
### Added
- Backwards compatibility wrapper for `generic_LFSR_8bit`
## 1.2.2 - 2018-03-09
### Added
- Backwards compatibility wrapper for `generic_fifo`
## 1.2.1 - 2018-03-09
### Fixed
- Fix an issue in the spill register which causes transactions to be lost
## 1.2.0 - 2018-03-09
### Added
- Add spill register
## 1.1.0 - 2018-03-06
### Added
- Find first zero
## 1.0.0 - 2018-03-02
### Added
- Re-implementation of the generic FIFO supporting all kinds of use-cases
- Testbench for FIFO
### Changed
- Re-formatting and artistic code clean-up
## 0.1.0 - 2018-02-23
### Added
- Fork of PULP common cells repository

View file

@ -0,0 +1,176 @@
SOLDERPAD HARDWARE LICENSE version 0.51
This license is based closely on the Apache License Version 2.0, but is not
approved or endorsed by the Apache Foundation. A copy of the non-modified
Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0.
As this license is not currently OSI or FSF approved, the Licensor permits any
Work licensed under this License, at the option of the Licensee, to be treated
as licensed under the Apache License Version 2.0 (which is so approved).
This License is licensed under the terms of this License and in particular
clause 7 below (Disclaimer of Warranties) applies in relation to its use.
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the Rights owner or entity authorized by the Rights owner
that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Rights" means copyright and any similar right including design right (whether
registered or unregistered), semiconductor topography (mask) rights and
database rights (but excluding Patents and Trademarks).
"Source" form shall mean the preferred form for making modifications, including
but not limited to source code, net lists, board layouts, CAD files,
documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object
code, generated documentation, the instantiation of a hardware design and
conversions to other media types, including intermediate forms such as
bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask
works).
"Work" shall mean the work of authorship, whether in Source form or other
Object form, made available under the License, as indicated by a Rights notice
that is included in or attached to the work (an example is provided in the
Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) or physically connect to or interoperate with the interfaces of, the Work
and Derivative Works thereof.
"Contribution" shall mean any design or work of authorship, including the
original version of the Work and any modifications or additions to that Work or
Derivative Works thereof, that is intentionally submitted to Licensor for
inclusion in the Work by the Rights owner or by an individual or Legal Entity
authorized to submit on behalf of the Rights owner. For the purposes of this
definition, "submitted" means any form of electronic, verbal, or written
communication sent to the Licensor or its representatives, including but not
limited to communication on electronic mailing lists, source code control
systems, and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but excluding
communication that is conspicuously marked or otherwise designated in writing
by the Rights owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of License. Subject to the terms and conditions of this License, each
Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable license under the Rights to reproduce,
prepare Derivative Works of, publicly display, publicly perform, sublicense,
and distribute the Work and such Derivative Works in Source or Object form and
do anything in relation to the Work as if the Rights did not exist.
3. Grant of Patent License. Subject to the terms and conditions of this
License, each Contributor hereby grants to You a perpetual, worldwide,
non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this
section) patent license to make, have made, use, offer to sell, sell, import,
and otherwise transfer the Work, where such license applies only to those
patent claims licensable by such Contributor that are necessarily infringed by
their Contribution(s) alone or by combination of their Contribution(s) with the
Work to which such Contribution(s) was submitted. If You institute patent
litigation against any entity (including a cross-claim or counterclaim in a
lawsuit) alleging that the Work or a Contribution incorporated within the Work
constitutes direct or contributory patent infringement, then any patent
licenses granted to You under this License for that Work shall terminate as of
the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or
Derivative Works thereof in any medium, with or without modifications, and in
Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy
of this License; and
You must cause any modified files to carry prominent notices stating that
You changed the files; and
You must retain, in the Source form of any Derivative Works that You
distribute, all copyright, patent, trademark, and attribution notices from
the Source form of the Work, excluding those notices that do not pertain to
any part of the Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then
any Derivative Works that You distribute must include a readable copy of
the attribution notices contained within such NOTICE file, excluding those
notices that do not pertain to any part of the Derivative Works, in at
least one of the following places: within a NOTICE text file distributed as
part of the Derivative Works; within the Source form or documentation, if
provided along with the Derivative Works; or, within a display generated by
the Derivative Works, if and wherever such third-party notices normally
appear. The contents of the NOTICE file are for informational purposes only
and do not modify the License. You may add Your own attribution notices
within Derivative Works that You distribute, alongside or as an addendum to
the NOTICE text from the Work, provided that such additional attribution
notices cannot be construed as modifying the License. You may add Your own
copyright statement to Your modifications and may provide additional or
different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a
whole, provided Your use, reproduction, and distribution of the Work
otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any
Contribution intentionally submitted for inclusion in the Work by You to the
Licensor shall be under the terms and conditions of this License, without any
additional terms or conditions. Notwithstanding the above, nothing herein shall
supersede or modify the terms of any separate license agreement you may have
executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names,
trademarks, service marks, or product names of the Licensor, except as required
for reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in
writing, Licensor provides the Work (and each Contributor provides its
Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied, including, without limitation, any warranties
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any risks
associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in
tort (including negligence), contract, or otherwise, unless required by
applicable law (such as deliberate and grossly negligent acts) or agreed to in
writing, shall any Contributor be liable to You for damages, including any
direct, indirect, special, incidental, or consequential damages of any
character arising as a result of this License or out of the use or inability to
use the Work (including but not limited to damages for loss of goodwill, work
stoppage, computer failure or malfunction, or any and all other commercial
damages or losses), even if such Contributor has been advised of the
possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or
Derivative Works thereof, You may choose to offer, and charge a fee for,
acceptance of support, warranty, indemnity, or other liability obligations
and/or rights consistent with this License. However, in accepting such
obligations, You may act only on Your own behalf and on Your sole
responsibility, not on behalf of any other Contributor, and only if You agree
to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View file

@ -0,0 +1,181 @@
[![Build Status](https://travis-ci.com/pulp-platform/common_cells.svg?branch=master)](https://travis-ci.com/pulp-platform/common_cells)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/pulp-platform/common_cells?color=blue&label=current&sort=semver)](CHANGELOG.md)
[![SHL-0.51 license](https://img.shields.io/badge/license-SHL--0.51-green)](LICENSE)
# Common Cells Repository
Maintainer: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
This repository contains commonly used cells and headers for use in various projects.
## Cell Contents
This repository currently contains the following cells, ordered by categories.
Please note that cells with status *deprecated* are not to be used for new designs and only serve to provide compatibility with old code.
### Clocks and Resets
| Name | Description | Status | Superseded By |
| ----------------------- | --------------------------------------------------- | ------------ | ------------- |
| `clk_div` | Clock divider with integer divisor | active | |
| `clock_divider` | Clock divider with configuration registers | *deprecated* | `clk_div` |
| `clock_divider_counter` | Clock divider using a counter | *deprecated* | `clk_div` |
| `rstgen` | Reset synchronizer | active | |
| `rstgen_bypass` | Reset synchronizer with dedicated test reset bypass | active | |
### Clock Domains and Asynchronous Crossings
| Name | Description | Status | Superseded By |
|--------------------------------|----------------------------------------------------------------------------------|--------------|---------------|
| `cdc_2phase` | Clock domain crossing using two-phase handshake, with ready/valid interface | active | |
| `cdc_fifo_2phase` | Clock domain crossing FIFO using two-phase handshake, with ready/valid interface | active | |
| `cdc_fifo_gray` | Clock domain crossing FIFO using a gray-counter, with ready/valid interface | active | |
| `edge_detect` | Rising/falling edge detector | active | |
| `edge_propagator` | **ANTONIO ADD DESCRIPTION** | active | |
| `edge_propagator_rx` | **ANTONIO ADD DESCRIPTION** | active | |
| `edge_propagator_tx` | **ANTONIO ADD DESCRIPTION** | active | |
| `isochronous_spill_register` | Isochronous clock domain crossing and full handshake (like `spill_register`) | active | |
| `isochronous_4phase_handshake` | Isochronous four-phase handshake. | active | |
| `pulp_sync` | Serial line synchronizer | *deprecated* | `sync` |
| `pulp_sync_wedge` | Serial line synchronizer with edge detector | *deprecated* | `sync_wedge` |
| `serial_deglitch` | Serial line deglitcher | active | |
| `sync` | Serial line synchronizer | active | |
| `sync_wedge` | Serial line synchronizer with edge detector | active | |
### Counters and Shift Registers
| Name | Description | Status | Superseded By |
| ------------------- | ----------------------------------------------------------------- | ------------ | ------------- |
| `counter` | Generic up/down counter with overflow detection | active | |
| `delta_counter` | Up/down counter with variable delta and overflow detection | active | |
| `generic_LFSR_8bit` | 8-bit linear feedback shift register (LFSR) | *deprecated* | `lfsr_8bit` |
| `lfsr_8bit` | 8-bit linear feedback shift register (LFSR) | active | |
| `lfsr_16bit` | 16-bit linear feedback shift register (LFSR) | active | |
| `lfsr` | 4...64-bit parametric Galois LFSR with optional whitening feature | active | |
| `max_counter` | Up/down counter with variable delta that tracks its maximum value | active | |
| `mv_filter` | **ZARUBAF ADD DESCRIPTION** | active | |
### Data Path Elements
| Name | Description | Status | Superseded By |
| -------------------------- | --------------------------------------------------------------------------------------------------------- | ------------ | ------------- |
| `addr_decode ` | Address map decoder | active | |
| `ecc_decode` | SECDED Decoder (Single Error Correction, Double Error Detection) | active | |
| `ecc_encode` | SECDED Encoder (Single Error Correction, Double Error Detection) | active | |
| `binary_to_gray` | Binary to gray code converter | active | |
| `find_first_one` | Leading-one finder / leading-zero counter | *deprecated* | `lzc` |
| `gray_to_binary` | Gray code to binary converter | active | |
| `lzc` | Leading/trailing-zero counter | active | |
| `onehot_to_bin` | One-hot to binary converter | active | |
| `shift_reg` | Shift register for arbitrary types | active | |
| `rr_arb_tree` | Round-robin arbiter for req/gnt and vld/rdy interfaces with optional priority | active | |
| `rrarbiter` | Round-robin arbiter for req/ack interface with look-ahead | *deprecated* | `rr_arb_tree` |
| `prioarbiter` | Priority arbiter arbiter for req/ack interface with look-ahead | *deprecated* | `rr_arb_tree` |
| `fall_through_register` | Fall-through register with ready/valid interface | active | |
| `spill_register_flushable` | Register with ready/valid interface to cut all combinational interface paths and additional flush signal. | active | |
| `spill_register` | Register with ready/valid interface to cut all combinational interface paths | active | |
| `stream_arbiter` | Round-robin arbiter for ready/valid stream interface | active | |
| `stream_arbiter_flushable` | Round-robin arbiter for ready/valid stream interface and flush functionality | active | |
| `stream_demux` | Ready/valid interface demultiplexer | active | |
| `stream_join` | Ready/valid handshake join multiple to one common | active | |
| `stream_mux` | Ready/valid interface multiplexer | active | |
| `stream_register` | Register with ready/valid interface | active | |
| `stream_fork` | Ready/valid fork | active | |
| `stream_fork_dynamic` | Ready/valid fork, with selection mask for partial forking | active | |
| `stream_filter` | Ready/valid filter | active | |
| `stream_delay` | Randomize or delay ready/valid interface | active | |
| `stream_to_mem` | Use memories without flow control for output data in streams. | active | |
| `stream_xbar` | Fully connected crossbar with ready/valid interface. | active | |
| `stream_omega_net` | One-way stream omega-net with ready/valid interface. Isomorphic to a butterfly. | active | |
| `sub_per_hash` | Substitution-permutation hash function | active | |
| `popcount` | Combinatorial popcount (hamming weight) | active | |
### Data Structures
| Name | Description | Status | Superseded By |
| ------------------ | ----------------------------------------------- | ------------ | ------------- |
| `cb_filter` | Counting-Bloom-Filter with combinational lookup | active | |
| `fifo` | FIFO register with upper threshold | *deprecated* | `fifo_v3` |
| `fifo_v2` | FIFO register with upper and lower threshold | *deprecated* | `fifo_v3` |
| `fifo_v3` | FIFO register with generic fill counts | active | |
| `stream_fifo` | FIFO register with ready/valid interface | active | |
| `generic_fifo` | FIFO register without thresholds | *deprecated* | `fifo_v3` |
| `generic_fifo_adv` | FIFO register without thresholds | *deprecated* | `fifo_v3` |
| `sram` | SRAM behavioral model | active | |
| `plru_tree` | Pseudo least recently used tree | active | |
| `unread` | Empty module to sink unconnected outputs into | active | |
## Header Contents
This repository currently contains the following header files.
### RTL Register Macros
The header file `registers.svh` contains macros that expand to descriptions of registers.
To avoid misuse of `always_ff` blocks, only the following macros shall be used to describe sequential behavior.
The use of linter rules that flag explicit uses of `always_ff` in source code is encouraged.
| Macro | Arguments | Description |
| ------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `` `FF`` | `q_sig`, `d_sig`, `rst_val`, (`clk_sig`, `arstn_sig`) | Flip-flop with asynchronous active-low reset |
| `` `FFAR`` | `q_sig`, `d_sig`, `rst_val`, `clk_sig`, `arst_sig` | Flip-flop with asynchronous active-high reset |
| `` `FFARN`` | `q_sig`, `d_sig`, `rst_val`, `clk_sig`, `arstn_sig` | *deprecated* Flip-flop with asynchronous active-low reset |
| `` `FFSR`` | `q_sig`, `d_sig`, `rst_val`, `clk_sig`, `rst_sig` | Flip-flop with synchronous active-high reset |
| `` `FFSRN`` | `q_sig`, `d_sig`, `rst_val`, `clk_sig`, `rstn_sig` | Flip-flop with synchronous active-low reset |
| `` `FFNR`` | `q_sig`, `d_sig`, `clk_sig` | Flip-flop without reset |
| | | |
| `` `FFL`` | `q_sig`, `d_sig`, `load_ena`, `rst_val`, (`clk_sig`, `arstn_sig`) | Flip-flop with load-enable and asynchronous active-low reset |
| `` `FFLAR`` | `q_sig`, `d_sig`, `load_ena`, `rst_val`, `clk_sig`, `arst_sig` | Flip-flop with load-enable and asynchronous active-high reset |
| `` `FFLARN`` | `q_sig`, `d_sig`, `load_ena`, `rst_val`, `clk_sig`, `arstn_sig` | *deprecated* Flip-flop with load-enable and asynchronous active-low reset |
| `` `FFLSR`` | `q_sig`, `d_sig`, `load_ena`, `rst_val`, `clk_sig`, `rst_sig` | Flip-flop with load-enable and synchronous active-high reset |
| `` `FFLSRN`` | `q_sig`, `d_sig`, `load_ena`, `rst_val`, `clk_sig`, `rstn_sig` | Flip-flop with load-enable and synchronous active-low reset |
| `` `FFLNR`` | `q_sig`, `d_sig`, `load_ena`, `clk_sig` | Flip-flop with load-enable without reset |
- *The name of the clock and reset signals for implicit variants is `clk_i` and `rst_ni`, respectively.*
- *Argument suffix `_sig` indicates signal names for present and next state as well as clocks and resets.*
- *Argument `rst_val` specifies the value literal to be assigned upon reset.*
- *Argument `load_ena` specifies the boolean expression that forms the load enable of the register.*
### SystemVerilog Assertion Macros
The header file `assertions.svh` contains macros that expand to assertion blocks.
These macros should recduce the effort in writing many assertions and make it
easier to use them. They are identical with the macros used by [lowrisc](https://github.com/lowRISC/opentitan/blob/master/hw/ip/prim/rtl/prim_assert.sv)
and just re-implemented here for the sake of easier use in PULP projects (the same include guard is used so they should not clash).
#### Simple Assertion and Cover Macros
| Macro | Arguments | Description |
| ----------------------------------------------------------- | -------------------------------------------------------------------------- | ----------- |
| `` `ASSERT_I`` | `__name`, `__prop` | Immediate assertion |
| `` `ASSERT_INIT`` | `__name`, `__prop` | Assertion in initial block. Can be used for things like parameter checking |
| `` `ASSERT_FINAL`` | `__name`, `__prop` | Assertion in final block |
| `` `ASSERT`` | `__name`, `__prop`, (`__clk`, `__rst`) | Assert a concurrent property directly |
| `` `ASSERT_NEVER`` | `__name`, `__prop`, (`__clk`, `__rst`) | Assert a concurrent property NEVER happens |
| `` `ASSERT_KNOWN`` | `__name`, `__sig`, (`__clk`, `__rst`) | Concurrent clocked assertion with custom error message |
| `` `COVER`` | `__name`, `__prop`, (`__clk`, `__rst`) | Cover a concurrent property |
- *The name of the clock and reset signals for implicit variants is `clk_i` and `rst_ni`, respectively.*
#### Complex Assertion Macros
| Macro | Arguments | Description |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------- |
| `` `ASSERT_PULSE`` | `__name`, `__sig`, (`__clk`, `__rst`) | Assert that signal is an active-high pulse with pulse length of 1 clock cycle |
| `` `ASSERT_IF`` | `__name`, `__prop`, `__enable`, (`__clk`, `__rst`) | Assert that a property is true only when an enable signal is set |
| `` `ASSERT_KNOWN_IF`` | `__name`, `__sig`, `__enable`, (`__clk`, `__rst`) | Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is set |
- *The name of the clock and reset signals for implicit variants is `clk_i` and `rst_ni`, respectively.*
#### Assumption Macros
| Macro | Arguments | Description |
| ------------------------------------------------------- | ---------------------------- | ----------- |
| `` `ASSUME`` | `__name`, `__prop`, (`__clk`, `__rst`) | Assume a concurrent property |
| `` `ASSUME_I`` | `__name`, `__prop` | Assume an immediate property |
- *The name of the clock and reset signals for implicit variants is `clk_i` and `rst_ni`, respectively.*
#### Formal Verification Macros
| Macro | Arguments | Description |
| ----------------------------------------------------------- | ------------------------------------------------------------ | ----------- |
| `` `ASSUME_FPV`` | `__name`, `__prop`, (`__clk`, `__rst`) | Assume a concurrent property during formal verification only |
| `` `ASSUME_I_FPV`` | `__name`, `__prop` | Assume a concurrent property during formal verification only |
| `` `COVER_FPV`` | `__name`, `__prop`, (`__clk`, `__rst`) | Cover a concurrent property during formal verification |
- *The name of the clock and reset signals for implicit variants is `clk_i` and `rst_ni`, respectively.*

View file

@ -0,0 +1,201 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// Macros and helper code for using assertions.
// - Provides default clk and rst options to simplify code
// - Provides boiler plate template for common assertions
`ifndef PRIM_ASSERT_SV
`define PRIM_ASSERT_SV
`ifdef UVM
// report assertion error with UVM if compiled
package assert_rpt_pkg;
import uvm_pkg::*;
`include "uvm_macros.svh"
function void assert_rpt(string msg);
`uvm_error("ASSERT FAILED", msg)
endfunction
endpackage
`endif
///////////////////
// Helper macros //
///////////////////
// local helper macro to reduce code clutter. undefined at the end of this file
`ifndef VERILATOR
`ifndef SYNTHESIS
`ifndef XSIM
`define INC_ASSERT
`endif
`endif
`endif
// Converts an arbitrary block of code into a Verilog string
`define PRIM_STRINGIFY(__x) `"__x`"
// ASSERT_RPT is available to change the reporting mechanism when an assert fails
`define ASSERT_RPT(__name) \
`ifdef UVM \
assert_rpt_pkg::assert_rpt($sformatf("[%m] %s (%s:%0d)", \
__name, `__FILE__, `__LINE__)); \
`else \
$error("[ASSERT FAILED] [%m] %s (%s:%0d)", __name, `__FILE__, `__LINE__); \
`endif
///////////////////////////////////////
// Simple assertion and cover macros //
///////////////////////////////////////
// Default clk and reset signals used by assertion macros below.
`define ASSERT_DEFAULT_CLK clk_i
`define ASSERT_DEFAULT_RST !rst_ni
// Immediate assertion
// Note that immediate assertions are sensitive to simulation glitches.
`define ASSERT_I(__name, __prop) \
`ifdef INC_ASSERT \
__name: assert (__prop) \
else begin \
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
end \
`endif
// Assertion in initial block. Can be used for things like parameter checking.
`define ASSERT_INIT(__name, __prop) \
`ifdef INC_ASSERT \
initial begin \
__name: assert (__prop) \
else begin \
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
end \
end \
`endif
// Assertion in final block. Can be used for things like queues being empty
// at end of sim, all credits returned at end of sim, state machines in idle
// at end of sim.
`define ASSERT_FINAL(__name, __prop) \
`ifdef INC_ASSERT \
final begin \
__name: assert (__prop || $test$plusargs("disable_assert_final_checks")) \
else begin \
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
end \
end \
`endif
// Assert a concurrent property directly.
// It can be called as a module (or interface) body item.
`define ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef INC_ASSERT \
__name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \
else begin \
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
end \
`endif
// Note: Above we use (__rst !== '0) in the disable iff statements instead of
// (__rst == '1). This properly disables the assertion in cases when reset is X at
// the beginning of a simulation. For that case, (reset == '1) does not disable the
// assertion.
// Assert a concurrent property NEVER happens
`define ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef INC_ASSERT \
__name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) not (__prop)) \
else begin \
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
end \
`endif
// Assert that signal has a known value (each bit is either '0' or '1') after reset.
// It can be called as a module (or interface) body item.
`define ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef INC_ASSERT \
`ASSERT(__name, !$isunknown(__sig), __clk, __rst) \
`endif
// Cover a concurrent property
`define COVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef INC_ASSERT \
__name: cover property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)); \
`endif
//////////////////////////////
// Complex assertion macros //
//////////////////////////////
// Assert that signal is an active-high pulse with pulse length of 1 clock cycle
`define ASSERT_PULSE(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef INC_ASSERT \
`ASSERT(__name, $rose(__sig) |=> !(__sig), __clk, __rst) \
`endif
// Assert that a property is true only when an enable signal is set. It can be called as a module
// (or interface) body item.
`define ASSERT_IF(__name, __prop, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef INC_ASSERT \
`ASSERT(__name, (__enable) |-> (__prop), __clk, __rst) \
`endif
// Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is
// set. It can be called as a module (or interface) body item.
`define ASSERT_KNOWN_IF(__name, __sig, __enable, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef INC_ASSERT \
`ASSERT_KNOWN(__name``KnownEnable, __enable, __clk, __rst) \
`ASSERT_IF(__name, !$isunknown(__sig), __enable, __clk, __rst) \
`endif
///////////////////////
// Assumption macros //
///////////////////////
// Assume a concurrent property
`define ASSUME(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef INC_ASSERT \
__name: assume property (@(posedge __clk) disable iff ((__rst) !== '0) (__prop)) \
else begin \
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
end \
`endif
// Assume an immediate property
`define ASSUME_I(__name, __prop) \
`ifdef INC_ASSERT \
__name: assume (__prop) \
else begin \
`ASSERT_RPT(`PRIM_STRINGIFY(__name)) \
end \
`endif
//////////////////////////////////
// For formal verification only //
//////////////////////////////////
// Note that the existing set of ASSERT macros specified above shall be used for FPV,
// thereby ensuring that the assertions are evaluated during DV simulations as well.
// ASSUME_FPV
// Assume a concurrent property during formal verification only.
`define ASSUME_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef FPV_ON \
`ASSUME(__name, __prop, __clk, __rst) \
`endif
// ASSUME_I_FPV
// Assume a concurrent property during formal verification only.
`define ASSUME_I_FPV(__name, __prop) \
`ifdef FPV_ON \
`ASSUME_I(__name, __prop) \
`endif
// COVER_FPV
// Cover a concurrent property during formal verification
`define COVER_FPV(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \
`ifdef FPV_ON \
`COVER(__name, __prop, __clk, __rst) \
`endif
`endif // PRIM_ASSERT_SV

View file

@ -0,0 +1,221 @@
// Copyright 2018, 2021 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// SPDX-License-Identifier: SHL-0.51
//
// Author: Stefan Mach <smach@iis.ee.ethz.ch>
// Description: Common register defines for RTL designs
`ifndef COMMON_CELLS_REGISTERS_SVH_
`define COMMON_CELLS_REGISTERS_SVH_
// Abridged Summary of available FF macros:
// `FF: asynchronous active-low reset
// `FFAR: asynchronous active-high reset
// `FFARN: [deprecated] asynchronous active-low reset
// `FFSR: synchronous active-high reset
// `FFSRN: synchronous active-low reset
// `FFNR: without reset
// `FFL: load-enable and asynchronous active-low reset
// `FFLAR: load-enable and asynchronous active-high reset
// `FFLARN: [deprecated] load-enable and asynchronous active-low reset
// `FFLARNC: load-enable and asynchronous active-low reset and synchronous active-high clear
// `FFLSR: load-enable and synchronous active-high reset
// `FFLSRN: load-enable and synchronous active-low reset
// `FFLNR: load-enable without reset
`ifdef VERILATOR
`define NO_SYNOPSYS_FF 1
`endif
`define REG_DFLT_CLK clk_i
`define REG_DFLT_RST rst_ni
// Flip-Flop with asynchronous active-low reset
// __q: Q output of FF
// __d: D input of FF
// __reset_value: value assigned upon reset
// (__clk: clock input)
// (__arst_n: asynchronous reset, active-low)
`define FF(__q, __d, __reset_value, __clk = `REG_DFLT_CLK, __arst_n = `REG_DFLT_RST) \
always_ff @(posedge (__clk) or negedge (__arst_n)) begin \
if (!__arst_n) begin \
__q <= (__reset_value); \
end else begin \
__q <= (__d); \
end \
end
// Flip-Flop with asynchronous active-high reset
// __q: Q output of FF
// __d: D input of FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __arst: asynchronous reset, active-high
`define FFAR(__q, __d, __reset_value, __clk, __arst) \
always_ff @(posedge (__clk) or posedge (__arst)) begin \
if (__arst) begin \
__q <= (__reset_value); \
end else begin \
__q <= (__d); \
end \
end
// DEPRECATED - use `FF instead
// Flip-Flop with asynchronous active-low reset
// __q: Q output of FF
// __d: D input of FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __arst_n: asynchronous reset, active-low
`define FFARN(__q, __d, __reset_value, __clk, __arst_n) \
`FF(__q, __d, __reset_value, __clk, __arst_n)
// Flip-Flop with synchronous active-high reset
// __q: Q output of FF
// __d: D input of FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __reset_clk: reset input, active-high
`define FFSR(__q, __d, __reset_value, __clk, __reset_clk) \
`ifndef NO_SYNOPSYS_FF \
/``* synopsys sync_set_reset `"__reset_clk`" *``/ \
`endif \
always_ff @(posedge (__clk)) begin \
__q <= (__reset_clk) ? (__reset_value) : (__d); \
end
// Flip-Flop with synchronous active-low reset
// __q: Q output of FF
// __d: D input of FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __reset_n_clk: reset input, active-low
`define FFSRN(__q, __d, __reset_value, __clk, __reset_n_clk) \
`ifndef NO_SYNOPSYS_FF \
/``* synopsys sync_set_reset `"__reset_n_clk`" *``/ \
`endif \
always_ff @(posedge (__clk)) begin \
__q <= (!__reset_n_clk) ? (__reset_value) : (__d); \
end
// Always-enable Flip-Flop without reset
// __q: Q output of FF
// __d: D input of FF
// __clk: clock input
`define FFNR(__q, __d, __clk) \
always_ff @(posedge (__clk)) begin \
__q <= (__d); \
end
// Flip-Flop with load-enable and asynchronous active-low reset (implicit clock and reset)
// __q: Q output of FF
// __d: D input of FF
// __load: load d value into FF
// __reset_value: value assigned upon reset
// (__clk: clock input)
// (__arst_n: asynchronous reset, active-low)
`define FFL(__q, __d, __load, __reset_value, __clk = `REG_DFLT_CLK, __arst_n = `REG_DFLT_RST) \
always_ff @(posedge (__clk) or negedge (__arst_n)) begin \
if (!__arst_n) begin \
__q <= (__reset_value); \
end else begin \
__q <= (__load) ? (__d) : (__q); \
end \
end
// Flip-Flop with load-enable and asynchronous active-high reset
// __q: Q output of FF
// __d: D input of FF
// __load: load d value into FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __arst: asynchronous reset, active-high
`define FFLAR(__q, __d, __load, __reset_value, __clk, __arst) \
always_ff @(posedge (__clk) or posedge (__arst)) begin \
if (__arst) begin \
__q <= (__reset_value); \
end else begin \
__q <= (__load) ? (__d) : (__q); \
end \
end
// DEPRECATED - use `FFL instead
// Flip-Flop with load-enable and asynchronous active-low reset
// __q: Q output of FF
// __d: D input of FF
// __load: load d value into FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __arst_n: asynchronous reset, active-low
`define FFLARN(__q, __d, __load, __reset_value, __clk, __arst_n) \
`FFL(__q, __d, __load, __reset_value, __clk, __arst_n)
// Flip-Flop with load-enable and synchronous active-high reset
// __q: Q output of FF
// __d: D input of FF
// __load: load d value into FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __reset_clk: reset input, active-high
`define FFLSR(__q, __d, __load, __reset_value, __clk, __reset_clk) \
`ifndef NO_SYNOPSYS_FF \
/``* synopsys sync_set_reset `"__reset_clk`" *``/ \
`endif \
always_ff @(posedge (__clk)) begin \
__q <= (__reset_clk) ? (__reset_value) : ((__load) ? (__d) : (__q)); \
end
// Flip-Flop with load-enable and synchronous active-low reset
// __q: Q output of FF
// __d: D input of FF
// __load: load d value into FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __reset_n_clk: reset input, active-low
`define FFLSRN(__q, __d, __load, __reset_value, __clk, __reset_n_clk) \
`ifndef NO_SYNOPSYS_FF \
/``* synopsys sync_set_reset `"__reset_n_clk`" *``/ \
`endif \
always_ff @(posedge (__clk)) begin \
__q <= (!__reset_n_clk) ? (__reset_value) : ((__load) ? (__d) : (__q)); \
end
// Flip-Flop with load-enable and asynchronous active-low reset and synchronous clear
// __q: Q output of FF
// __d: D input of FF
// __load: load d value into FF
// __clear: assign reset value into FF
// __reset_value: value assigned upon reset
// __clk: clock input
// __arst_n: asynchronous reset, active-low
`define FFLARNC(__q, __d, __load, __clear, __reset_value, __clk, __arst_n) \
`ifndef NO_SYNOPSYS_FF \
/``* synopsys sync_set_reset `"__clear`" *``/ \
`endif \
always_ff @(posedge (__clk) or negedge (__arst_n)) begin \
if (!__arst_n) begin \
__q <= (__reset_value); \
end else begin \
__q <= (__clear) ? (__reset_value) : (__load) ? (__d) : (__q); \
end \
end
// Load-enable Flip-Flop without reset
// __q: Q output of FF
// __d: D input of FF
// __load: load d value into FF
// __clk: clock input
`define FFLNR(__q, __d, __load, __clk) \
always_ff @(posedge (__clk)) begin \
__q <= (__load) ? (__d) : (__q); \
end
`endif

View file

@ -0,0 +1,161 @@
// Copyright 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Wolfgang Roenninger <wroennin@ethz.ch>
/// Address Decoder: Maps the input address combinatorially to an index.
/// The address map `addr_map_i` is a packed array of rule_t structs.
/// The ranges of any two rules may overlap. If so, the rule at the higher (more significant)
/// position in `addr_map_i` prevails.
///
/// There can be an arbitrary number of address rules. There can be multiple
/// ranges defined for the same index. The start address has to be less than the end address.
///
/// There is the possibility to add a default mapping:
/// `en_default_idx_i`: Driving this port to `1'b1` maps all input addresses
/// for which no rule in `addr_map_i` exists to the default index specified by
/// `default_idx_i`. In this case, `dec_error_o` is always `1'b0`.
///
/// Assertions: The module checks every time there is a change in the address mapping
/// if the resulting map is valid. It fatals if `start_addr` is higher than `end_addr`
/// or if a mapping targets an index that is outside the number of allowed indices.
/// It issues warnings if the address regions of any two mappings overlap.
module addr_decode #(
/// Highest index which can happen in a rule.
parameter int unsigned NoIndices = 32'd0,
/// Total number of rules.
parameter int unsigned NoRules = 32'd0,
/// Address type inside the rules and to decode.
parameter type addr_t = logic,
/// Rule packed struct type.
/// The address decoder expects three fields in `rule_t`:
///
/// typedef struct packed {
/// int unsigned idx;
/// addr_t start_addr;
/// addr_t end_addr;
/// } rule_t;
///
/// - `idx`: index of the rule, has to be < `NoIndices`
/// - `start_addr`: start address of the range the rule describes, value is included in range
/// - `end_addr`: end address of the range the rule describes, value is NOT included in range
parameter type rule_t = logic,
/// Dependent parameter, do **not** overwite!
///
/// Width of the `idx_o` output port.
parameter int unsigned IdxWidth = cf_math_pkg::idx_width(NoIndices),
/// Dependent parameter, do **not** overwite!
///
/// Type of the `idx_o` output port.
parameter type idx_t = logic [IdxWidth-1:0]
) (
/// Address to decode.
input addr_t addr_i,
/// Address map: rule with the highest array position wins on collision
input rule_t [NoRules-1:0] addr_map_i,
/// Decoded index.
output idx_t idx_o,
/// Decode is valid.
output logic dec_valid_o,
/// Decode is not valid, no matching rule found.
output logic dec_error_o,
/// Enable default port mapping.
///
/// When not used, tie to `0`.
input logic en_default_idx_i,
/// Default port index.
///
/// When `en_default_idx_i` is `1`, this will be the index when no rule matches.
///
/// When not used, tie to `0`.
input idx_t default_idx_i
);
logic [NoRules-1:0] matched_rules; // purely for address map debugging
always_comb begin
// default assignments
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;
// match the rules
for (int unsigned i = 0; i < NoRules; i++) begin
if ((addr_i >= addr_map_i[i].start_addr) && (addr_i < addr_map_i[i].end_addr)) begin
matched_rules[i] = 1'b1;
dec_valid_o = 1'b1;
dec_error_o = 1'b0;
idx_o = idx_t'(addr_map_i[i].idx);
end
end
end
// Assumptions and assertions
`ifndef VERILATOR
`ifndef XSIM
// pragma translate_off
initial begin : proc_check_parameters
assume ($bits(addr_i) == $bits(addr_map_i[0].start_addr)) else
$warning($sformatf("Input address has %d bits and address map has %d bits.",
$bits(addr_i), $bits(addr_map_i[0].start_addr)));
assume (NoRules > 0) else
$fatal(1, $sformatf("At least one rule needed"));
assume (NoIndices > 0) else
$fatal(1, $sformatf("At least one index needed"));
end
assert final ($onehot0(matched_rules)) else
$warning("More than one bit set in the one-hot signal, matched_rules");
// These following assumptions check the validity of the address map.
// The assumptions gets generated for each distinct pair of rules.
// Each assumption is present two times, as they rely on one rules being
// effectively ordered. Only one of the rules with the same function is
// active at a time for a given pair.
// check_start: Enforces a smaller start than end address.
// check_idx: Enforces a valid index in the rule.
// check_overlap: Warns if there are overlapping address regions.
always @(addr_map_i) #0 begin : proc_check_addr_map
if (!$isunknown(addr_map_i)) begin
for (int unsigned i = 0; i < NoRules; i++) begin
check_start : assume (addr_map_i[i].start_addr < addr_map_i[i].end_addr) else
$fatal(1, $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));
// check the SLV ids
check_idx : assume (addr_map_i[i].idx < NoIndices) else
$fatal(1, $sformatf("This rule has a IDX that is not allowed!!!\n\
Violating rule %d.\n\
Rule> IDX: %h START: %h END: %h\n\
Rule> MAX_IDX: %h\n\
#####################################################",
i, addr_map_i[i].idx, addr_map_i[i].start_addr, addr_map_i[i].end_addr,
(NoIndices-1)));
for (int unsigned j = i + 1; j < NoRules; j++) begin
// overlap check
check_overlap : assume (!((addr_map_i[j].start_addr < addr_map_i[i].end_addr) &&
(addr_map_i[j].end_addr > addr_map_i[i].start_addr))) else
$warning($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));
end
end
end
end
// pragma translate_on
`endif
`endif
endmodule

View file

@ -0,0 +1,22 @@
// Copyright 2018 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A binary to gray code converter.
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

View file

@ -0,0 +1,246 @@
// Copyright (c) 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Wolfgang Roenninger <wroennin@ethz.ch>
// `cb_filter`: This module implements a counting bloom filter with parameterizable hash functions.
//
// Functionality: A counting bloom filter is a data structure to efficiently implement
// set lookups. It does so by hashing its data inputs onto multiple pointers
// which serve as indicators for an array of buckets. For lookups can be
// false positives, but no false negatives.
// - Seeding: The pseudo random generators need seeds at elaboration time to generate
// different hashes. In principle any combination of seeds can be used.
// But one should look that the hash outputs give sufficient different patterns,
// such that the resulting collision rate is low. The package `cb_filter_pkg`
// contains the struct for seeding the PRG's in the hash functions.
// - Lookup:
// - Ports: `look_data_i`, `look_valid_o`
// - Description: Lookup combinational, `look_valid_o` is high, when `look_data_i` was
// previously put into the filter.
// - Increment:
// - Ports: `incr_data_i`, `incr_valid_i`
// - Description: Put data into the counting bloom filter, when valid is high.
// - Decrement:
// - Ports: `decr_data_i`, `decr_valid_i`
// - Description: Remove data from the counting bloom filter. Only remove data that was
// previously put in, otherwise will go in a wrong state.
// - Status:
// - `filter_clear_i`: Clears the filter and sets all counters to 0.
// - `filter_ussage_o`: How many data items are currently in the filter.
// - `filter_full_o`: Filter is full, can no longer hold more items.
// - `filter_empty_o`: Filter is empty.
// - `filter_error_o`: One of the internal counters or buckets overflowed.
/// This is a counting bloom filter
module cb_filter #(
parameter int unsigned KHashes = 32'd3, // Number of hash functions
parameter int unsigned HashWidth = 32'd4, // Number of counters is 2**HashWidth
parameter int unsigned HashRounds = 32'd1, // Number of permutation substitution rounds
parameter int unsigned InpWidth = 32'd32, // Input data width
parameter int unsigned BucketWidth = 32'd4, // Width of Bucket counters
// the seeds used for seeding the PRG's inside each hash, one `cb_seed_t` per hash function.
parameter cb_filter_pkg::cb_seed_t [KHashes-1:0] Seeds = cb_filter_pkg::EgSeeds
) (
input logic clk_i, // Clock
input logic rst_ni, // Active low reset
// data lookup
input logic [InpWidth-1:0] look_data_i,
output logic look_valid_o,
// data increment
input logic [InpWidth-1:0] incr_data_i,
input logic incr_valid_i,
// data decrement
input logic [InpWidth-1:0] decr_data_i,
input logic decr_valid_i,
// status signals
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;
// signal declarations
logic [NoCounters-1:0] look_ind; // hash function pointers
logic [NoCounters-1:0] incr_ind; // hash function pointers
logic [NoCounters-1:0] decr_ind; // hash function pointers
// bucket (counter signals)
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;
// membership lookup signals
logic [NoCounters-1:0] data_in_bucket;
// tot count signals (filter usage)
logic cnt_en;
logic cnt_down;
logic cnt_overflow;
// -----------------------------------------
// Lookup Hash - Membership Detection
// -----------------------------------------
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;
// -----------------------------------------
// Increment Hash - Add Member to Set
// -----------------------------------------
hash_block #(
.NoHashes ( KHashes ),
.InpWidth ( InpWidth ),
.HashWidth ( HashWidth ),
.NoRounds ( HashRounds ),
.Seeds ( Seeds )
) i_incr_hashes (
.data_i ( incr_data_i ),
.indicator_o ( incr_ind )
);
// -----------------------------------------
// Decrement Hash - Remove Member from Set
// -----------------------------------------
hash_block #(
.NoHashes ( KHashes ),
.InpWidth ( InpWidth ),
.HashWidth ( HashWidth ),
.NoRounds ( HashRounds ),
.Seeds ( Seeds )
) i_decr_hashes (
.data_i ( decr_data_i ),
.indicator_o ( decr_ind )
);
// -----------------------------------------
// Control the incr/decr of buckets
// -----------------------------------------
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; // unreachable
endcase
end
// -----------------------------------------
// Counters
// -----------------------------------------
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
// -----------------------------------------
// Filter tot item counter
// -----------------------------------------
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 )
);
// -----------------------------------------
// Filter Output Flags
// -----------------------------------------
assign filter_full_o = |bucket_full;
assign filter_empty_o = &bucket_empty;
assign filter_error_o = |bucket_overflow | cnt_overflow;
endmodule
// gives out the or 'onehots' of all hash functions
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 ( ), // not used, because we want the onehot
.hash_onehot_o ( hashes[i] )
);
end
// output assignment
always_comb begin : proc_hash_or
indicator_o = '0;
for (int unsigned i = 0; i < (2**HashWidth); i++) begin
for (int unsigned j = 0; j < NoHashes; j++) begin
indicator_o[i] = indicator_o[i] | hashes[j][i];
end
end
end
// assertions
// pragma translate_off
initial begin
hash_conf: assume (InpWidth > HashWidth) else
$fatal(1, "%m:\nA Hash Function reduces the width of the input>\nInpWidth: %s\nOUT_WIDTH: %s",
InpWidth, HashWidth);
end
// pragma translate_on
endmodule

View file

@ -0,0 +1,26 @@
// Copyright (c) 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Wolfgang Roenninger <wroennin@ethz.ch>
/// Package with the struct definition for the seeds and an example.
package cb_filter_pkg;
typedef struct packed {
int unsigned PermuteSeed;
int unsigned XorSeed;
} cb_seed_t;
// example seeding struct
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

View file

@ -0,0 +1,50 @@
// Copyright 2021 ETH Zurich.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/// Hardware implementation of SystemVerilog's `$onehot()` function.
/// It uses a tree of half adders and a separate
/// or reduction tree for the carry.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
// Author: Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// Author: Stefan Mach <smach@iis.ee.ethz.ch>
module cc_onehot #(
parameter int unsigned Width = 4
) (
input logic [Width-1:0] d_i,
output logic is_onehot_o
);
// trivial base case
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;
// Extend to a power of two.
assign sum[0] = $unsigned(d_i);
// generate half adders for each lvl
// lvl 0 is the input level
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
// generate carry tree
assign carry_array[i-1] = |carry[i][LVLWidth/2-1:0];
end
assign is_onehot_o = sum[LVLS-1][0] & ~|carry_array;
end
endmodule

View file

@ -0,0 +1,175 @@
// Copyright 2018 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A two-phase clock domain crossing.
///
/// CONSTRAINT: Requires max_delay of min_period(src_clk_i, dst_clk_i) through
/// the paths async_req, async_ack, async_data.
/* 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
);
// Asynchronous handshake signals.
(* dont_touch = "true" *) logic async_req;
(* dont_touch = "true" *) logic async_ack;
(* dont_touch = "true" *) T async_data;
// The sender in the source domain.
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 )
);
// The receiver in the destination domain.
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
/// Half of the two-phase clock domain crossing located in the source domain.
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;
// The req_src and data_src registers change when a new data item is accepted.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
req_src_q <= 0;
data_src_q <= '0;
end else if (valid_i && ready_o) begin
req_src_q <= ~req_src_q;
data_src_q <= data_i;
end
end
// The ack_src and ack registers act as synchronization stages.
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
// Output assignments.
assign ready_o = (req_src_q == ack_q);
assign async_req_o = req_src_q;
assign async_data_o = data_src_q;
endmodule
/// Half of the two-phase clock domain crossing located in the destination
/// domain.
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;
// The ack_dst register changes when a new data item is accepted.
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
// The data_dst register changes when a new data item is presented. This is
// indicated by the async_req line changing levels.
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
data_dst_q <= '0;
end else if (req_q0 != req_q1 && !valid_o) begin
data_dst_q <= async_data_i;
end
end
// The req_dst and req registers act as synchronization stages.
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
// Output assignments.
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 */

View file

@ -0,0 +1,134 @@
// Copyright 2018 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A clock domain crossing FIFO, using 2-phase hand shakes.
///
/// This FIFO has its push and pop ports in two separate clock domains. Its size
/// can only be powers of two, which is why its depth is given as 2**LOG_DEPTH.
/// LOG_DEPTH must be at least 1.
///
/// CONSTRAINT: See the constraints for `cdc_2phase`. An additional maximum
/// delay path needs to be specified from fifo_data_q to dst_data_o.
module cdc_fifo_2phase #(
/// The data type of the payload transported by the FIFO.
parameter type T = logic,
/// The FIFO's depth given as 2**LOG_DEPTH.
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
);
// Check the invariants.
//pragma translate_off
initial begin
assert(LOG_DEPTH > 0);
end
//pragma translate_on
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;
// Allocate the registers for the FIFO memory with its separate write and read
// ports. The FIFO has the following ports:
//
// - write: fifo_widx, fifo_wdata, fifo_write, src_clk_i
// - read: fifo_ridx, fifo_rdata
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] <= '0;
else if (fifo_write && fifo_widx == i)
fifo_data_q[i] <= fifo_wdata;
end
end
// Allocate the read and write pointers in the source and destination domain.
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
// The pointers into the FIFO are one bit wider than the actual address into
// the FIFO. This makes detecting critical states very simple: if all but the
// topmost bit of rptr and wptr agree, the FIFO is in a critical state. If the
// topmost bit is equal, the FIFO is empty, otherwise it is full.
assign src_ready_o = ((src_wptr_q ^ src_rptr) != PtrFull);
assign dst_valid_o = ((dst_rptr_q ^ dst_wptr) != PtrEmpty);
// Transport the read and write pointers across the clock domain boundary.
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 )
);
// Drive the FIFO write and read ports.
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

View file

@ -0,0 +1,269 @@
// Copyright 2018-2019 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
// Florian Zaruba <zarubaf@iis.ee.ethz.ch>
/// A clock domain crossing FIFO, using gray counters.
///
/// # Architecture
///
/// The design is split into two parts, each one being clocked and reset
/// separately.
/// 1. The data to be transferred over the clock domain boundary is
/// is stored in a FIFO. The corresponding write pointer is managed
/// (incremented) in the source clock domain.
/// 2. The entire FIFO content is exposed over the `async_data` port.
/// The destination clock domain increments its read pointer
/// in its destination clock domain.
///
/// Read and write pointers are then gray coded, communicated
/// and synchronized using a classic multi-stage FF synchronizer
/// in the other clock domain. The gray coding ensures that only
/// one bit changes at each pointer increment, preventing the
/// synchronizer to accidentally latch an inconsistent state
/// on a multi-bit bus.
///
/// The not full signal e.g. `src_ready_o` (on the sending side)
/// is generated using the local write pointer and the pessimistic
/// read pointer from the destination clock domain (pessimistic
/// because it is delayed at least two cycles because of the synchronizer
/// stages). This prevents the FIFO from overflowing.
///
/// The not empty signal e.g. `dst_valid_o` is generated using
/// the pessimistic write pointer and the local read pointer in
/// the destination clock domain. This means the FIFO content
/// does not need to be synchronized as we are sure we are reading
/// data which has been written at least two cycles earlier.
/// Furthermore, the read select logic into the FIFO is completely
/// clocked by the destination clock domain which avoids
/// inefficient data synchronization.
///
/// The FIFO size must be powers of two, which is why its depth is
/// given as 2**LOG_DEPTH. LOG_DEPTH must be at least 1.
///
/// # Constraints
///
/// We need to make sure that the propagation delay of the
/// data, read and write pointer is bound to the minimum of
/// either the sending or receiving clock period to prevent
/// an inconsistent state to be latched (if for example the one
/// bit of the read/write pointer have an excessive delay).
/// Furthermore, we should deactivate setup and hold checks on
/// the asynchronous signals.
///
/// ```
/// set_ungroup [get_designs cdc_fifo_gray*] false
/// set_boundary_optimization [get_designs cdc_fifo_gray*] false
/// set_max_delay min(T_src, T_dst) \
/// -through [get_pins -hierarchical -filter async] \
/// -through [get_pins -hierarchical -filter async]
/// set_false_path -hold \
/// -through [get_pins -hierarchical -filter async] \
/// -through [get_pins -hierarchical -filter async]
/// ```
`include "common_cells/registers.svh"
(* no_ungroup *)
(* no_boundary_optimization *)
module cdc_fifo_gray #(
/// The width of the default logic type.
parameter int unsigned WIDTH = 1,
/// The data type of the payload transported by the FIFO.
parameter type T = logic [WIDTH-1:0],
/// The FIFO's depth given as 2**LOG_DEPTH.
parameter int LOG_DEPTH = 3,
/// The number of synchronization registers to insert on the async pointers.
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 )
);
// Check the invariants.
// pragma translate_off
`ifndef VERILATOR
initial assert(LOG_DEPTH > 0);
initial assert(SYNC_STAGES >= 2);
`endif
// pragma translate_on
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;
logic [PtrWidth-1:0] wptr_q, wptr_d, wptr_bin, wptr_next, rptr, rptr_bin;
// Data FIFO.
assign async_data_o = data_q;
for (genvar i = 0; i < 2**LOG_DEPTH; i++) begin : gen_word
`FFLNR(data_q[i], src_data_i,
src_valid_i & src_ready_o & (wptr_bin[LOG_DEPTH-1:0] == i), src_clk_i)
end
// Read pointer.
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));
// Write pointer.
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));
`FFLARN(wptr_q, wptr_d, src_valid_i & src_ready_o, '0, src_clk_i, src_rst_ni)
assign async_wptr_o = wptr_q;
// The pointers into the FIFO are one bit wider than the actual address into
// the FIFO. This makes detecting critical states very simple: if all but the
// topmost bit of rptr and wptr agree, the FIFO is in a critical state. If the
// topmost bit is equal, the FIFO is empty, otherwise it is full.
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;
// Data selector and register.
assign dst_data = async_data_i[rptr_bin[LOG_DEPTH-1:0]];
// Read pointer.
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));
`FFLARN(rptr_q, rptr_d, dst_valid & dst_ready, '0, dst_clk_i, dst_rst_ni)
assign async_rptr_o = rptr_q;
// Write pointer.
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));
// The pointers into the FIFO are one bit wider than the actual address into
// the FIFO. This makes detecting critical states very simple: if all but the
// topmost bit of rptr and wptr agree, the FIFO is in a critical state. If the
// topmost bit is equal, the FIFO is empty, otherwise it is full.
assign dst_valid = ((wptr_bin ^ rptr_bin) != PtrEmpty);
// Cut the combinatorial path with a spill register.
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

View file

@ -0,0 +1,61 @@
// Copyright 2016 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/// cf_math_pkg: Constant Function Implementations of Mathematical Functions for HDL Elaboration
///
/// This package contains a collection of mathematical functions that are commonly used when defining
/// the value of constants in HDL code. These functions are implemented as Verilog constants
/// functions. Introduced in Verilog 2001 (IEEE Std 1364-2001), a constant function (§ 10.3.5) is a
/// function whose value can be evaluated at compile time or during elaboration. A constant function
/// must be called with arguments that are constants.
package cf_math_pkg;
/// Ceiled Division of Two Natural Numbers
///
/// Returns the quotient of two natural numbers, rounded towards plus infinity.
function automatic integer ceil_div (input longint dividend, input longint divisor);
automatic longint remainder;
// pragma translate_off
`ifndef VERILATOR
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
`endif
// pragma translate_on
remainder = dividend;
for (ceil_div = 0; remainder > 0; ceil_div++) begin
remainder = remainder - divisor;
end
endfunction
/// Index width required to be able to represent up to `num_idx` indices as a binary
/// encoded signal.
/// Ensures that the minimum width if an index signal is `1`, regardless of parametrization.
///
/// Sample usage in type definition:
/// As parameter:
/// `parameter type idx_t = logic[cf_math_pkg::idx_width(NumIdx)-1:0]`
/// As typedef:
/// `typedef logic [cf_math_pkg::idx_width(NumIdx)-1:0] idx_t`
function automatic integer unsigned idx_width (input integer unsigned num_idx);
return (num_idx > 32'd1) ? unsigned'($clog2(num_idx)) : 32'd1;
endfunction
endpackage

View file

@ -0,0 +1,42 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba
// Description: Divides the clock by an integer factor
module clk_div #(
parameter int unsigned RATIO = 4
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic testmode_i, // testmode
input logic en_i, // enable clock divider
output logic clk_o // divided clock out
);
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
// output assignment - bypass in testmode
assign clk_o = testmode_i ? clk_i : clk_q;
endmodule

View file

@ -0,0 +1,43 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba
// Description: Generic up/down counter
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, // synchronous clear
input logic en_i, // enable the counter
input logic load_i, // load a new value
input logic down_i, // downcount, default is up
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

View file

@ -0,0 +1,74 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Up/down counter with variable delta
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, // synchronous clear
input logic en_i, // enable the counter
input logic load_i, // load a new value
input logic down_i, // downcount, default is up
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) overflow_q <= ~rst_ni ? 1'b0 : overflow_d;
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
// counter overflowed if the MSB is set
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

View file

@ -0,0 +1,191 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// //
// Company: Multitherman Laboratory @ DEIS - University of Bologna //
// Viale Risorgimento 2 40136 //
// Bologna - fax 0512093785 - //
// //
// Engineer: Antonio Pullini - pullinia@iis.ee.ethz.ch //
// //
// Additional contributions by: //
// //
// //
// //
// Create Date: 13/02/2013 //
// Design Name: ULPSoC //
// Module Name: clock_divider //
// Project Name: ULPSoC //
// Language: SystemVerilog //
// //
// Description: Clock Divider //
// //
// //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (19/03/2015) clock_gating swapped in pulp_clock_gating //
// //
// //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
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;
`ifndef PULP_FPGA_EMUL
rstgen i_rst_gen
(
// PAD FRAME SIGNALS
.clk_i(clk_i),
.rst_ni(rstn_i), //async signal coming from pads
// TEST MODE
.test_mode_i(test_mode_i),
// OUTPUT RESET
.rst_no(s_rstn_sync),
.init_no() //not used
);
`else
assign s_rstn_sync = rstn_i;
`endif
//handle the handshake with the soc_ctrl. Interface is now async
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
//sample the data when valid has been sync and there is a rise edge
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
//sample the data when valid has been sync and there is a rise edge
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

View file

@ -0,0 +1,211 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// Company: Multitherman Laboratory @ DEIS - University of Bologna //
// Viale Risorgimento 2 40136 //
// Bologna - fax 0512093785 - //
// //
// Engineer: Antonio Pullini - pullinia@iis.ee.ethz.ch //
// //
// Additional contributions by: //
// //
// //
// //
// Create Date: 13/02/2013 //
// Design Name: ULPSoC //
// Module Name: clock_divider_counter //
// Project Name: ULPSoC //
// Language: SystemVerilog //
// //
// Description: clock_divider_counter //
// //
// //
// Revision: //
// Revision v0.1 - File Created //
// Revision v0.2 - (19/03/2015) clock_gating swapped in pulp_clock_gating //
// //
// //
// //
// //
// //
// //
////////////////////////////////////////////////////////////////////////////////
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_incr = clk_div + 1;
// assign clk_cnt_odd = {1'b0,clk_cnt_odd_incr[7:1]}; //if odd divider than clk_cnt = (clk_div+1)/2
assign clk_cnt_odd = clk_div - 8'h1; //if odd divider than clk_cnt = clk_div - 1
assign clk_cnt_even = (clk_div == 8'h2) ? 8'h0 : ({1'b0,clk_div[7:1]} - 8'h1); //if even divider than clk_cnt = clk_div/2
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)
);
`ifndef PULP_FPGA_EMUL
`ifdef PULP_DFT
pulp_clock_mux2 clk_muxinv_i
(
.clk0_i(clk_inv),
.clk1_i(clk),
.clk_sel_i(test_mode),
.clk_o(clk_inv_test)
);
`else
assign clk_inv_test = clk_inv;
`endif
`else
assign clk_inv_test = clk_inv;
`endif
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 // always_ff @ (posedge clk_inv_test or negedge rstn)
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

View file

@ -0,0 +1,57 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
/* verilator lint_off DECLFILENAME */
module fifo #(
parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode
parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic
parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32
parameter int unsigned THRESHOLD = 1, // fill count until when to assert threshold_o
parameter type dtype = logic [DATA_WIDTH-1:0]
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the queue
input logic testmode_i, // test_mode to bypass clock gating
// status flags
output logic full_o, // queue is full
output logic empty_o, // queue is empty
output logic threshold_o, // the FIFO is above the specified threshold
// as long as the queue is not full we can push new data
input dtype data_i, // data to push into the queue
input logic push_i, // data is valid and can be pushed to the queue
// as long as the queue is not empty we can pop new elements
output dtype data_o, // output data
input logic pop_i // pop head from queue
);
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 */

View file

@ -0,0 +1,79 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module fifo_v2 #(
parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode
parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic
parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32
parameter int unsigned ALM_EMPTY_TH = 1, // almost empty threshold (when to assert alm_empty_o)
parameter int unsigned ALM_FULL_TH = 1, // almost full threshold (when to assert alm_full_o)
parameter type dtype = logic [DATA_WIDTH-1:0],
// DO NOT OVERWRITE THIS PARAMETER
parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the queue
input logic testmode_i, // test_mode to bypass clock gating
// status flags
output logic full_o, // queue is full
output logic empty_o, // queue is empty
output logic alm_full_o, // FIFO fillstate >= the specified threshold
output logic alm_empty_o, // FIFO fillstate <= the specified threshold
// as long as the queue is not full we can push new data
input dtype data_i, // data to push into the queue
input logic push_i, // data is valid and can be pushed to the queue
// as long as the queue is not empty we can pop new elements
output dtype data_o, // output data
input logic pop_i // pop head from queue
);
logic [ADDR_DEPTH-1:0] usage;
// generate threshold parameters
if (DEPTH == 0) begin
assign alm_full_o = 1'b0; // that signal does not make any sense in a FIFO of depth 0
assign alm_empty_o = 1'b0; // that signal does not make any sense in a FIFO of depth 0
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
);
// pragma translate_off
`ifndef VERILATOR
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
`endif
// pragma translate_on
endmodule // fifo_v2

View file

@ -0,0 +1,83 @@
// Copyright 2018 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Deprecated, use lzc unit instead.
/// A leading-one finder / leading zero counter.
/// Set FLIP to 0 for find_first_one => first_one_o is the index of the first one (from the LSB)
/// Set FLIP to 1 for leading zero counter => first_one_o is the number of leading zeroes (from the MSB)
module find_first_one #(
/// The width of the input vector.
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);
// pragma translate_off
initial begin
assert(WIDTH >= 0);
end
// pragma translate_on
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 two successive indices are still in the vector...
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 only the first index is still in the vector...
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 index is out of range
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

View file

@ -0,0 +1,64 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Igor Loi <igor.loi@unibo.it>
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, // One hot encoding
output logic [BIN_WIDTH-1:0] data_BIN_o, // Binary encoding
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;
//-------------Code Starts Here-------
assign linear_feedback = !(out[7] ^ out[3] ^ out[2] ^ out[1]); // TAPS for XOR feedback
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
// Bin to One Hot Encoder
always_comb
begin
data_OH_o = '0;
data_OH_o[temp_ref_way] = 1'b1;
end
endmodule

View file

@ -0,0 +1,274 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// ============================================================================= //
// Company: Multitherman Laboratory @ DEIS - University of Bologna //
// Viale Risorgimento 2 40136 //
// Bologna - fax 0512093785 - //
// //
// Engineer: Igor Loi - igor.loi@unibo.it //
// //
// //
// Additional contributions by: //
// //
// //
// //
// Create Date: 01/02/2014 //
// Design Name: MISC //
// Module Name: generic_fifo //
// Project Name: PULP //
// Language: SystemVerilog //
// //
// Description: A simple FIFO used in the D_address_decoder, and D_allocator //
// to store the destinations ports //
// //
// Revision: //
// Revision v0.1 - 01/02/2014 : File Created //
// Revision v0.2 - 02/09/2015 : Updated with a global CG cell //
// //
// ============================================================================= //
module generic_fifo
#(
parameter int unsigned DATA_WIDTH = 32,
parameter int unsigned DATA_DEPTH = 8
)
(
input logic clk,
input logic rst_n,
//PUSH SIDE
input logic [DATA_WIDTH-1:0] data_i,
input logic valid_i,
output logic grant_o,
//POP SIDE
output logic [DATA_WIDTH-1:0] data_o,
output logic valid_o,
input logic grant_i,
input logic test_mode_i
);
// Local Parameter
localparam int unsigned ADDR_DEPTH = $clog2(DATA_DEPTH);
enum logic [1:0] { EMPTY, FULL, MIDDLE } CS, NS;
// Internal Signals
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;
// Parameter Check
// synopsys translate_off
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
// synopsys translate_on
`ifndef PULP_FPGA_EMUL
cluster_clock_gating cg_cell
(
.clk_i ( clk ),
.en_i (~gate_clock ),
.test_en_i ( test_mode_i ),
.clk_o ( clk_gated )
);
`else
assign clk_gated = clk;
`endif
// UPDATE THE STATE
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
// Compute Next State
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//~EMPTY
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 // end of FULL
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 // generic_fifo

View file

@ -0,0 +1,264 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Igor Loi <igor.loi@unibo.it>
module generic_fifo_adv
#(
parameter int unsigned DATA_WIDTH = 32,
parameter int unsigned DATA_DEPTH = 8
)
(
input logic clk,
input logic rst_n,
input logic clear_i,
//PUSH SIDE
input logic [DATA_WIDTH-1:0] data_i,
input logic valid_i,
output logic grant_o,
//POP SIDE
output logic [DATA_WIDTH-1:0] data_o,
output logic valid_o,
input logic grant_i,
input logic test_mode_i
);
// Local Parameter
localparam int unsigned ADDR_DEPTH = $clog2(DATA_DEPTH);
enum logic [1:0] { EMPTY, FULL, MIDDLE } CS, NS;
// Internal Signals
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;
// Parameter Check
// synopsys translate_off
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
// synopsys translate_on
`ifndef PULP_FPGA_EMUL
cluster_clock_gating cg_cell
(
.clk_i ( clk ),
.en_i (~gate_clock ),
.test_en_i ( test_mode_i ),
.clk_o ( clk_gated )
);
`else
assign clk_gated = clk;
`endif
// UPDATE THE STATE
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
if(clear_i)
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
end
// Compute Next State
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//~EMPTY
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 // end of FULL
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 // generic_fifo

View file

@ -0,0 +1,89 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>, ETH Zurich
// Date: 16.03.2019
// Description: Priority arbiter with Lock in. Port 0 has priority over port 1, port 1 over port2
// and so on. If the `LOCK_IN` feature is activated the arbitration decision is kept
// when the `en_i` is low.
// Dependencies: relies on fast leading zero counter tree "onehot_to_bin" in common_cells
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, // clears the fsm and control signal registers
input logic en_i, // arbiter enable
input logic [NUM_REQ-1:0] req_i, // request signals
output logic [NUM_REQ-1:0] ack_o, // acknowledge signals
output logic vld_o, // request ack'ed
output logic [$clog2(NUM_REQ)-1:0] idx_o // idx output
);
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;
// shared
assign vld_o = (|req_i) & en_i;
assign idx_o = (lock_q) ? arb_sel_lock_q : idx;
// Arbiter
// Port 0 has priority over all other ports
assign ack_o[0] = (req_i[0]) ? en_i : 1'b0;
// check that the priorities
for (genvar i = 1; i < NUM_REQ; i++) begin : gen_arb_req_ports
// for every subsequent port check the priorities of the previous port
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
// latch decision in case we got at least one req and no acknowledge
assign lock_d = (|req_i) & ~en_i;
assign arb_sel_lock_d = idx_o;
end else begin
// disable
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

View file

@ -0,0 +1,36 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Antonio Pullini <pullinia@iis.ee.ethz.ch>
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

View file

@ -0,0 +1,55 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Antonio Pullini <pullinia@iis.ee.ethz.ch>
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

View file

@ -0,0 +1,61 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
// Date: 16.08.2018
// Description: Fair round robin arbiter with lock feature.
//
// The rrarbiter employs fair round robin arbitration - i.e. the priorities
// rotate each cycle.
//
// The lock-in feature prevents the arbiter from changing the arbitration
// decision when the arbiter is disabled. I.e., the index of the first request
// that wins the arbitration will be locked until en_i is asserted again.
//
// Dependencies: relies on rr_arb_tree from common_cells.
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, // clears arbiter state
input logic en_i, // arbiter enable
input logic [NUM_REQ-1:0] req_i, // request signals
output logic [NUM_REQ-1:0] ack_o, // acknowledge signals
output logic vld_o, // request ack'ed
output logic [$clog2(NUM_REQ)-1:0] idx_o // idx output
);
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

View file

@ -0,0 +1,46 @@
// Copyright 2017, 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Date: 13.10.2017
// Description: SRAM Behavioral Model
module sram #(
int unsigned DATA_WIDTH = 64,
int unsigned NUM_WORDS = 1024
)(
input logic clk_i,
input logic req_i,
input logic we_i,
input logic [$clog2(NUM_WORDS)-1:0] addr_i,
input logic [DATA_WIDTH-1:0] wdata_i,
input logic [DATA_WIDTH-1:0] be_i,
output logic [DATA_WIDTH-1:0] rdata_o
);
localparam ADDR_WIDTH = $clog2(NUM_WORDS);
logic [DATA_WIDTH-1:0] ram [NUM_WORDS-1:0];
logic [ADDR_WIDTH-1:0] raddr_q;
// 1. randomize array
// 2. randomize output when no request is active
always_ff @(posedge clk_i) begin
if (req_i) begin
if (!we_i)
raddr_q <= addr_i;
else
for (int i = 0; i < DATA_WIDTH; i++)
if (be_i[i]) ram[addr_i][i] <= wdata_i[i];
end
end
assign rdata_o = ram[raddr_q];
endmodule

View file

@ -0,0 +1,128 @@
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
//
/// # ECC Decoder
///
/// Implements SECDED (Single Error Correction, Double Error Detection) Hamming Code
/// with extended parity bit [1].
/// The module receives a data word including parity bit and decodes it according to the
/// number of data and parity bit.
///
/// 1. If no error has been detected, the syndrome will be zero and all flags will be zero.
/// 2. If a single error has been detected, the syndrome is non-zero, and `single_error_o` will be
/// asserted. The output word contains the corrected data.
/// 3. If the parity bit contained an error, the module will assert `parity_error_o`.
/// 4. In case of a double fault the syndrome is non-zero, `double_error_o` will be asserted.
/// All other status flags will be de-asserted.
///
/// [1] https://en.wikipedia.org/wiki/Hamming_code
module ecc_decode import ecc_pkg::*; #(
/// Data width of unencoded word.
parameter int unsigned DataWidth = 64,
// Do not change
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;
}
) (
/// Encoded data in
input encoded_data_t data_i,
/// Corrected data out
output data_t data_o,
/// Error syndrome indicates the erroneous bit position
output parity_t syndrome_o,
/// A single error occurred
output logic single_error_o,
/// Error received in parity bit (MSB)
output logic parity_error_o,
/// A double error occurred
output logic double_error_o
);
logic parity;
data_t data_wo_parity;
parity_t syndrome;
logic syndrome_not_zero;
code_word_t correct_data;
// Check parity bit. 0 = parity equal, 1 = different parity
assign parity = data_i.parity ^ (^data_i.code_word);
///! | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
///! |p1 p2 d1 p4 d2 d3 d4 p8 d5 d6 d7 d8 d9 d10 d11
///! ---|----------------------------------------------
///! p1 | x x x x x x x x
///! p2 | x x x x x x x x
///! p4 | x x x x x x x x
///! p8 | x x x x x x x x
///! 1. Parity bit 1 covers all bit positions which have the least significant bit
///! set: bit 1 (the parity bit itself), 3, 5, 7, 9, etc.
///! 2. Parity bit 2 covers all bit positions which have the second least
///! significant bit set: bit 2 (the parity bit itself), 3, 6, 7, 10, 11, etc.
///! 3. Parity bit 4 covers all bit positions which have the third least
///! significant bit set: bits 47, 1215, 2023, etc.
///! 4. Parity bit 8 covers all bit positions which have the fourth least
///! significant bit set: bits 815, 2431, 4047, etc.
///! 5. In general each parity bit covers all bits where the bitwise AND of the
///! parity position and the bit position is non-zero.
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;
// correct the data word if the syndrome is non-zero
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
///! Syndrome | Overall Parity (MSB) | Error Type | Notes
///! --------------------------------------------------------
///! 0 | 0 | No Error |
///! /=0 | 1 | Single Error | Correctable. Syndrome holds incorrect bit position.
///! 0 | 1 | Parity Error | Overall parity, MSB is in error and can be corrected.
///! /=0 | 0 | Double Error | Not correctable.
assign single_error_o = parity & syndrome_not_zero;
assign parity_error_o = parity & ~syndrome_not_zero;
assign double_error_o = ~parity & syndrome_not_zero;
// Extract data vector
always_comb begin
automatic int unsigned idx; // bit index
data_wo_parity = '0;
idx = 0;
for (int unsigned i = 1; i < unsigned'($bits(code_word_t)) + 1; i++) begin
// if i is a power of two we are indexing a parity bit
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

View file

@ -0,0 +1,78 @@
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
/// # ECC Encoder
///
/// Implements SECDED (Single Error Correction, Double Error Detection) Hamming Code
/// with extended parity bit [1].
/// The module receives a data word and encodes it using above mentioned error
/// detection and correction code. The corresponding decode module
/// can be found in `ecc_decode.sv`
///
/// [1] https://en.wikipedia.org/wiki/Hamming_code
module ecc_encode import ecc_pkg::*; #(
/// Data width of unencoded word.
parameter int unsigned DataWidth = 64,
// Do not change
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;
}
) (
/// Unencoded data in
input data_t data_i,
/// Encoded data out
output encoded_data_t data_o
);
parity_t parity_code_word;
code_word_t data, codeword;
// Expand incoming data to codeword width
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 it is not a power of two word it is a normal data index
if (unsigned'(2**$clog2(i)) != i) begin
data[i - 1] = data_i[idx];
idx++;
end
end
end
// calculate code word
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
// fuse the final codeword
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

View file

@ -0,0 +1,31 @@
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
//
/// Contains common ECC definitions and helper functions.
package ecc_pkg;
// Calculate required ECC parity width:
function automatic int unsigned get_parity_width (input int unsigned data_width);
// data_width + cw_width + 1 <= 2**cw_width
int unsigned cw_width = 2;
while (unsigned'(2**cw_width) < cw_width + data_width + 1) cw_width++;
return cw_width;
endfunction
// Calculate required ECC codeword width:
function automatic int unsigned get_cw_width (input int unsigned data_width);
// data width + parity width + one additional parity bit (for double error detection)
return data_width + get_parity_width(data_width);
endfunction
endpackage

View file

@ -0,0 +1,32 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba
// Description: Edge detector, clock needs to oversample for proper edge detection
module edge_detect (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic d_i, // data stream in
output logic re_o, // rising edge detected
output logic fe_o // falling edge detected
);
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

View file

@ -0,0 +1,50 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Antonio Pullini <pullinia@iis.ee.ethz.ch>
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
);
logic [1:0] sync_a;
logic sync_b;
logic r_input_reg;
logic s_input_reg_next;
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 i_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

View file

@ -0,0 +1,31 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Antonio Pullini <pullinia@iis.ee.ethz.ch>
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

View file

@ -0,0 +1,40 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Antonio Pullini <pullinia@iis.ee.ethz.ch>
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

View file

@ -0,0 +1,98 @@
// Copyright 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
// Date: 10.04.2019
// Description: exponential backoff counter with randomization.
//
// For each failed trial (set_i pulsed), this unit exponentially increases the
// (average) backoff time by masking an LFSR with a shifted mask in order to
// create the backoff counter initial value.
//
// The shift register mask and the counter value are both reset to '0 in case of
// a successful trial (clr_i).
//
module exp_backoff #(
/// Seed for 16bit LFSR
parameter int unsigned Seed = 'hffff,
/// 2**MaxExp-1 determines the maximum range from which random wait counts are drawn
parameter int unsigned MaxExp = 16
) (
input logic clk_i,
input logic rst_ni,
/// Sets the backoff counter (pulse) -> use when trial did not succeed
input logic set_i,
/// Clears the backoff counter (pulse) -> use when trial succeeded
input logic clr_i,
/// Indicates whether the backoff counter is equal to zero and a new trial can be launched
output logic is_zero_o
);
// leave this constant
localparam int unsigned WIDTH = 16;
logic [WIDTH-1:0] lfsr_d, lfsr_q, cnt_d, cnt_q, mask_d, mask_q;
logic lfsr;
// generate random wait counts
// note: we use a flipped lfsr here to
// avoid strange correlation effects between
// the (left-shifted) mask and the 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;
// mask the wait counts with exponentially increasing mask (shift reg)
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
///////////////////////////////////////////////////////
// assertions
///////////////////////////////////////////////////////
//pragma translate_off
`ifndef VERILATOR
initial begin
// assert wrong parameterizations
assert (MaxExp>0)
else $fatal(1,"MaxExp must be greater than 0");
assert (MaxExp<=16)
else $fatal(1,"MaxExp cannot be greater than 16");
assert (Seed>0)
else $fatal(1,"Zero seed is not allowed for LFSR");
end
`endif
//pragma translate_on
endmodule // exp_backoff

View file

@ -0,0 +1,58 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Fall-through register with a simple stream-like ready/valid handshake.
// This register does not cut combinatorial paths on any signals: in case the module at its output
// is ready to accept data within the same clock cycle, they are forwarded. Use this module to get a
// 'default ready' behavior towards the input.
module fall_through_register #(
parameter type T = logic // Vivado requires a default value for type parameters.
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous active-low reset
input logic clr_i, // Synchronous clear
input logic testmode_i, // Test mode to bypass clock gating
// Input port
input logic valid_i,
output logic ready_o,
input T data_i,
// Output port
output logic valid_o,
input logic ready_i,
output T data_o
);
logic fifo_empty,
fifo_full;
fifo_v2 #(
.FALL_THROUGH (1'b1),
.DATA_WIDTH ($size(T)),
.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),
.alm_full_o ( ),
.alm_empty_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

View file

@ -0,0 +1,154 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
module fifo_v3 #(
parameter bit FALL_THROUGH = 1'b0, // fifo is in fall-through mode
parameter int unsigned DATA_WIDTH = 32, // default data width if the fifo is of type logic
parameter int unsigned DEPTH = 8, // depth can be arbitrary from 0 to 2**32
parameter type dtype = logic [DATA_WIDTH-1:0],
// DO NOT OVERWRITE THIS PARAMETER
parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the queue
input logic testmode_i, // test_mode to bypass clock gating
// status flags
output logic full_o, // queue is full
output logic empty_o, // queue is empty
output logic [ADDR_DEPTH-1:0] usage_o, // fill pointer
// as long as the queue is not full we can push new data
input dtype data_i, // data to push into the queue
input logic push_i, // data is valid and can be pushed to the queue
// as long as the queue is not empty we can pop new elements
output dtype data_o, // output data
input logic pop_i // pop head from queue
);
// local parameter
// FIFO depth - handle the case of pass-through, synthesizer will do constant propagation
localparam int unsigned FifoDepth = (DEPTH > 0) ? DEPTH : 1;
// clock gating control
logic gate_clock;
// pointer to the read and write section of the queue
logic [ADDR_DEPTH - 1:0] read_pointer_n, read_pointer_q, write_pointer_n, write_pointer_q;
// keep a counter to keep track of the current queue status
// this integer will be truncated by the synthesis tool
logic [ADDR_DEPTH:0] status_cnt_n, status_cnt_q;
// actual memory
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
// status flags
// read and write queue logic
always_comb begin : read_write_comb
// default assignment
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;
// push a new element to the queue
if (push_i && ~full_o) begin
// push the data onto the queue
mem_n[write_pointer_q] = data_i;
// un-gate the clock, we want to write something
gate_clock = 1'b0;
// increment the write counter
if (write_pointer_q == FifoDepth[ADDR_DEPTH-1:0] - 1)
write_pointer_n = '0;
else
write_pointer_n = write_pointer_q + 1;
// increment the overall counter
status_cnt_n = status_cnt_q + 1;
end
if (pop_i && ~empty_o) begin
// read from the queue is a default assignment
// but increment the read pointer...
if (read_pointer_n == FifoDepth[ADDR_DEPTH-1:0] - 1)
read_pointer_n = '0;
else
read_pointer_n = read_pointer_q + 1;
// ... and decrement the overall count
status_cnt_n = status_cnt_q - 1;
end
// keep the count pointer stable if we push and pop at the same time
if (push_i && pop_i && ~full_o && ~empty_o)
status_cnt_n = status_cnt_q;
// FIFO is in pass through mode -> do not change the pointers
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
// sequential process
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 <= '0;
end else if (!gate_clock) begin
mem_q <= mem_n;
end
end
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (DEPTH > 0) else $error("DEPTH must be greater than 0.");
end
full_write : assert property(
@(posedge clk_i) disable iff (~rst_ni) (full_o |-> ~push_i))
else $fatal (1, "Trying to push new data although the FIFO is full.");
empty_read : assert property(
@(posedge clk_i) disable iff (~rst_ni) (empty_o |-> ~pop_i))
else $fatal (1, "Trying to pop data although the FIFO is empty.");
`endif
// pragma translate_on
endmodule // fifo_v3

View file

@ -0,0 +1,23 @@
// Copyright 2018 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A gray code to binary converter.
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

View file

@ -0,0 +1,419 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// ID Queue
//
// In an ID queue, every element has a numeric ID. Among all elements that have the same ID, the ID
// queue preserves FIFO order.
//
// This ID queue implementation allows to either push (through the `inp_*` signals) or pop (through
// the `oup_*` signals) one element per clock cycle (depending on the _FULL_BW_ operating mode
// descibed below). The `inp_` port has priority and grants a request iff the queue is not full. The
// `oup_` port dequeues an element iff `oup_pop_i` is asserted during an `oup_` handshake;
// otherwise, it performs a non-destructive read. `oup_data_o` is valid iff `oup_data_valid_o` is
// asserted during an `oup_` handshake. If `oup_data_valid_o` is not asserted, the queue did not
// contain an element with the provided ID.
//
// The queue can work in two bandwidth modes:
// * !FULL_BW: Input and output cannot be performed simultaneously (max bandwidth: 50%).
// * FULL_BW: Input and output can be performed simultaneously and a popped cell can be reused
// immediately in the same clock cycle. Area increase typically 5-10%.
//
// This ID queue additionally provides the `exists_` port, which searches for an element anywhere in
// the queue. The comparison performed during the search can be masked: for every bit that is
// asserted in `exists_mask_i`, the corresponding bit in the queue element and in `exists_data_i`
// must be equal for a match; the other bits are not compared. If masking is not required, tie
// `exists_mask_i_ to `'1` and the synthesizer should simplify the comparisons to unmasked ones. The
// `exists_` port operates independently of the `inp_` and `oup_` ports. If the `exists_` port is
// unused, tie `exists_req_i` to `1'b0` and the synthesizer should remove the internal comparators.
//
// This ID queue can store at most `CAPACITY` elements, independent of their ID. Let
// - C = `CAPACITY`
// - B = $bits(data_t)
// - I = 2**`ID_WIDTH`
// Then
// - the queue element storage requires O(C * (B + log2(C))) bit
// - the ID table requires O(H * log2(C)) bit, where H = min(C, I)
//
// Maintainers:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
module id_queue #(
parameter int ID_WIDTH = 0,
parameter int CAPACITY = 0,
parameter bit FULL_BW = 0,
parameter type data_t = logic,
// Dependent parameters, DO NOT OVERRIDE!
localparam type id_t = logic[ID_WIDTH-1:0],
localparam type mask_t = logic[$bits(data_t)-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 exists_data_i,
input mask_t exists_mask_i,
input logic exists_req_i,
output logic exists_o,
output logic 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
);
// Capacity of the head-tail table, which associates an ID with corresponding head and tail
// indices.
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);
// Type for indexing the head-tail table.
typedef logic [HtIdxWidth-1:0] ht_idx_t;
// Type for indexing the lined data table.
typedef logic [LdIdxWidth-1:0] ld_idx_t;
// Type of an entry in the head-tail table.
typedef struct packed {
id_t id;
ld_idx_t head,
tail;
logic free;
} head_tail_t;
// Type of an entry in the linked data table.
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 [CAPACITY-1:0] exists_match,
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;
// Find the index in the head-tail table that matches a given ID.
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 )
);
// Find the first free index in the head-tail table.
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 ) // Start at index 0.
) i_ht_free_lzc (
.in_i ( head_tail_free ),
.cnt_o ( head_tail_free_idx ),
.empty_o ( )
);
// Find the first free index in the linked data table.
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 ) // Start at index 0.
) i_ld_free_lzc (
.in_i ( linked_data_free ),
.cnt_o ( linked_data_free_idx ),
.empty_o ( )
);
// The queue is full if and only if there are no free items in the linked data structure.
assign full = !(|linked_data_free);
// Data potentially freed by the output.
assign oup_data_free_idx = head_tail_q[match_out_idx].head;
// Data can be accepted if the linked list pool is not full, or some data is simultaneously.
assign inp_gnt_o = ~full || (oup_data_popped && FULL_BW);
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 the ID does not yet exist in the queue, add a new ID entry.
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
};
// Otherwise append it to the existing ID subqueue.
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
// Set free bit of linked data entry, all other bits are don't care.
linked_data_d[head_tail_q[match_in_idx].head] = '0;
linked_data_d[head_tail_q[match_in_idx].head][0] = 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
// Always grant the output request. If there was no match, the default, invalid entry
// will be returned.
oup_gnt_o = 1'b1;
end
end else begin
// FULL_BW
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;
// Set free bit of linked data entry, all other bits are don't care.
linked_data_d[head_tail_q[match_out_idx].head] = '0;
linked_data_d[head_tail_q[match_out_idx].head][0] = 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
// Always grant the output request. If there was no match, the default, invalid entry
// will be returned.
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 the ID does not yet exist in the queue or was just popped, add a new ID entry.
if (oup_ht_popped && (oup_id_i==inp_id_i)) begin
// If output data was popped for this ID, which lead the head_tail to be popped,
// then repopulate this head_tail immediately.
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
// Else, if no head_tail corresponds to the input id.
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
// Otherwise append it to the existing ID subqueue.
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
// Exists Lookup
for (genvar i = 0; i < CAPACITY; i++) begin: gen_lookup
mask_t exists_match_bits;
for (genvar j = 0; j < $bits(data_t); j++) begin: gen_mask
always_comb begin
if (linked_data_q[i].free) begin
exists_match_bits[j] = 1'b0;
end else begin
if (!exists_mask_i[j]) begin
exists_match_bits[j] = 1'b1;
end else begin
exists_match_bits[j] = (linked_data_q[i].data[j] == exists_data_i[j]);
end
end
end
end
assign exists_match[i] = (&exists_match_bits);
end
always_comb begin
exists_gnt_o = 1'b0;
exists_o = '0;
if (exists_req_i) begin
exists_gnt_o = 1'b1;
exists_o = (|exists_match);
end
end
// Registers
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
// Set free bit of linked data entries, all other bits are don't care.
linked_data_q[i] <= '0;
linked_data_q[i][0] <= 1'b1;
end else begin
linked_data_q[i] <= linked_data_d[i];
end
end
end
// Validate parameters.
// pragma translate_off
`ifndef VERILATOR
initial begin: validate_params
assert (ID_WIDTH >= 1)
else $fatal(1, "The ID must at least be one bit wide!");
assert (CAPACITY >= 1)
else $fatal(1, "The queue must have capacity of at least one entry!");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,81 @@
// Copyright 2020 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
/// 4-phase handshake between isochronous clock domains
/// (i.e., clock domains which operate on an integer multiple of each other).
///
/// The internals of this modules are similar to a clock-domain crossing except that
/// they do not synchronize the handshake signals as signals can not become metastable (covered by STA).
/// The upstream circuit will only handshake iff the downstream circuit handshaked.
///
/// ## Optionally Passing of Data
///
/// If the passing of data is necessary this should be done out side the module, for example:
/// ```
/// `FFLNR(dst_data_o, src_data_i, (src_valid_i && src_ready_o), src_clk_i)
/// ```
///
/// This module differs to `isochronous_spill_register` that it doesn't buffer any data
/// and only toggles the source handshake once the destination handshake has been toggled.
///
/// # Restrictions
///
/// Source and destination clock domains must be an integer multiple of each other and
/// all timing-paths need to be covered by STA. For example a recommended SDC would be:
///
/// `create_generated_clock dst_clk_i -name dst_clk -source src_clk_i -divide_by 2
///
/// There are _no_ restrictions on which clock domain should be the faster, any integer
/// ratio will work.
`include "common_cells/registers.svh"
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;
// source is making a request
`FFLARN(src_req_q, ~src_req_q, (src_valid_i && src_ready_o), 1'b0, src_clk_i, src_rst_ni)
// "synchronize" the acknowledge into the sending clock-domain
`FFARN(src_ack_q, dst_ack_q, 1'b0, src_clk_i, src_rst_ni)
// source is ready if the request wasn't yet acknowledged
assign src_ready_o = (src_req_q == src_ack_q);
// down-stream circuit is acknowledging the handshake
`FFLARN(dst_ack_q, ~dst_ack_q, (dst_valid_o && dst_ready_i), 1'b0, dst_clk_i, dst_rst_ni)
// "synchronize" the request into the receiving clock domain
`FFARN(dst_req_q, src_req_q, 1'b0, dst_clk_i, dst_rst_ni)
// destination is valid if we didn't yet get acknowledge
assign dst_valid_o = (dst_req_q != dst_ack_q);
// pragma translate_off
// stability guarantees
`ifndef VERILATOR
assert property (@(posedge src_clk_i) disable iff (src_rst_ni)
(src_valid_i && !src_ready_o |=> $stable(src_valid_i))) else $error("src_valid_i is unstable");
assert property (@(posedge dst_clk_i) disable iff (dst_rst_ni)
(dst_valid_o && !dst_ready_i |=> $stable(dst_valid_o))) else $error("dst_valid_o is unstable");
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,111 @@
// Copyright 2020 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Florian Zaruba <zarubaf@iis.ee.ethz.ch>
`include "common_cells/registers.svh"
/// A register with handshakes that completely cuts any combinatorial paths
/// between the input and output in isochronous clock domains.
///
/// > Definition of isochronous: In telecommunication, an isochronous signal is a signal
/// > in which the time interval separating any two significant instants is equal to the
/// > unit interval or a multiple of the unit interval.
///
/// The source and destination clock domains must be derived from the same clock
/// but can vary in frequency by a constant factor (e.g., double the frequency).
///
/// The module is basically a two deep dual-clock fifo with read and write pointers
/// in different clock domains. As we know the static timing relationship between the
/// clock domains we can rely on static timing analysis (STA) to get the sampling windows
/// right and therefore don't need any synchronization.
///
/// # Restrictions
///
/// Source and destination clock domains must be an integer multiple of each other and
/// all timing-paths need to be covered by STA. For example a recommended SDC would be:
///
/// `create_generated_clock dst_clk_i -name dst_clk -source src_clk_i -divide_by 2
///
/// There are _no_ restrictions on which clock domain should be the faster, any integer
/// ratio will work.
module isochronous_spill_register #(
/// Data type of spill register.
parameter type T = logic,
/// Make this spill register transparent.
parameter bit Bypass = 1'b0
) (
/// Clock of source clock domain.
input logic src_clk_i,
/// Active low async reset in source domain.
input logic src_rst_ni,
/// Source input data is valid.
input logic src_valid_i,
/// Source is ready to accept.
output logic src_ready_o,
/// Source input data.
input T src_data_i,
/// Clock of destination clock domain.
input logic dst_clk_i,
/// Active low async reset in destination domain.
input logic dst_rst_ni,
/// Destination output data is valid.
output logic dst_valid_o,
/// Destination is ready to accept.
input logic dst_ready_i,
/// Destination output data.
output T dst_data_o
);
// Don't generate the spill register.
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;
// Generate the spill register
end else begin : gen_isochronous_spill_register
/// Read/write pointer are one bit wider than necessary.
/// We implicitly capture the full and empty state with the second bit:
/// If all but the topmost bit of `rd_pointer_q` and `wr_pointer_q` agree, the
/// FIFO is in a critical state. If the topmost bit is equal, the FIFO is
/// empty, otherwise it is full.
logic [1:0] rd_pointer_q, wr_pointer_q;
// Advance write pointer if we pushed a new item into the FIFO. (Source clock domain)
`FFLARN(wr_pointer_q, wr_pointer_q+1, (src_valid_i && src_ready_o), '0, src_clk_i, src_rst_ni)
// Advance read pointer if downstream consumed an item. (Destination clock domain)
`FFLARN(rd_pointer_q, rd_pointer_q+1, (dst_valid_o && dst_ready_i), '0, dst_clk_i, dst_rst_ni)
T [1:0] mem_d, mem_q;
`FFLNR(mem_q, mem_d, (src_valid_i && src_ready_o), src_clk_i)
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
// pragma translate_off
// stability guarantees
`ifndef VERILATOR
assert property (@(posedge src_clk_i) disable iff (src_rst_ni)
(src_valid_i && !src_ready_o |=> $stable(src_valid_i))) else $error("src_valid_i is unstable");
assert property (@(posedge src_clk_i) disable iff (src_rst_ni)
(src_valid_i && !src_ready_o |=> $stable(src_data_i))) else $error("src_data_i is unstable");
assert property (@(posedge dst_clk_i) disable iff (dst_rst_ni)
(dst_valid_o && !dst_ready_i |=> $stable(dst_valid_o))) else $error("dst_valid_o is unstable");
assert property (@(posedge dst_clk_i) disable iff (dst_rst_ni)
(dst_valid_o && !dst_ready_i |=> $stable(dst_data_o))) else $error("dst_data_o is unstable");
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,315 @@
// Copyright 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
// Date: 26.04.2019
//
// Description: This is a parametric LFSR with precomputed coefficients for
// LFSR lengths from 4 to 64bit.
// Additional block cipher layers can be instantiated to non-linearly transform
// the pseudo-random LFSR sequence at the output, and hence break the shifting
// patterns. The additional cipher layers can only be used for an LFSR width
// of 64bit, since the block cipher has been designed for that block length.
module lfsr #(
parameter int unsigned LfsrWidth = 64, // [4,64]
parameter int unsigned OutWidth = 8, // [1,LfsrWidth]
parameter logic [LfsrWidth-1:0] RstVal = '1, // [1,2^LfsrWidth-1]
// 0: disabled, the present cipher uses 31, but just a few layers (1-3) are enough
// to break linear shifting patterns
parameter int unsigned CipherLayers = 0,
parameter bit CipherReg = 1'b1 // additional output reg after cipher
) (
input logic clk_i,
input logic rst_ni,
input logic en_i,
output logic [OutWidth-1:0] out_o
);
// Galois LFSR feedback masks
// Automatically generated with get_lfsr_masks.py
// Masks are from https://users.ece.cmu.edu/~koopman/lfsr/
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};
// this S-box and permutation P has been taken from the Present Cipher,
// a super lightweight block cipher. use the cipher layers to add additional
// non-linearity to the LFSR output. note one layer does not fully correspond
// to the present cipher round, since the key and rekeying function is not applied here.
//
// See also:
// "PRESENT: An Ultra-Lightweight Block Cipher", A. Bogdanov et al., Ches 2007
// http://www.lightweightcrypto.org/present/present_ches2007.pdf
// this is the sbox from the present cipher
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 };
// these are the permutation indices of the present cipher
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;
//for (logic [4:0] j = '0; j<16; j++) out[j*4 +: 4] = sbox4[in[j*4 +: 4]];
// this simulates much faster than the loop
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;
// for (logic [7:0] j = '0; j<64; j++) out[perm[j]] = in[j];
// this simulates much faster than the loop
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
////////////////////////////////////////////////////////////////////////
// lfsr
////////////////////////////////////////////////////////////////////////
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
//$display("%b %h", en_i, lfsr_d);
if (!rst_ni) begin
lfsr_q <= LfsrWidth'(RstVal);
end else begin
lfsr_q <= lfsr_d;
end
end
////////////////////////////////////////////////////////////////////////
// block cipher layers
////////////////////////////////////////////////////////////////////////
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
// additiona output reg after cipher
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
// no outreg
end else begin : g_no_out_reg
assign out_o = ciph_layer[OutWidth-1:0];
end
// no block cipher
end else begin : g_no_cipher_layers
assign out_o = lfsr_q[OutWidth-1:0];
end
////////////////////////////////////////////////////////////////////////
// assertions
////////////////////////////////////////////////////////////////////////
// pragma translate_off
initial begin
// these are the LUT limits
assert(OutWidth <= LfsrWidth) else
$fatal(1,"OutWidth must be smaller equal the LfsrWidth.");
assert(RstVal > unsigned'(0)) else
$fatal(1,"RstVal must be nonzero.");
assert((LfsrWidth >= $low(Masks)) && (LfsrWidth <= $high(Masks))) else
$fatal(1,"Unsupported LfsrWidth.");
assert(Masks[LfsrWidth][LfsrWidth-1]) else
$fatal(1, "LFSR mask is not correct. The MSB must be 1." );
assert((CipherLayers > 0) && (LfsrWidth == 64) || (CipherLayers == 0)) else
$fatal(1, "Use additional cipher layers only in conjunction with an LFSR width of 64 bit." );
end
`ifndef VERILATOR
all_zero: assert property (
@(posedge clk_i) disable iff (!rst_ni) en_i |-> lfsr_d)
else $fatal(1,"Lfsr must not be all-zero.");
`endif
// pragma translate_on
endmodule // lfsr

View file

@ -0,0 +1,68 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba, ETH Zurich
// Date: 5.11.2018
// Description: 16-bit LFSR
// --------------
// 16-bit LFSR
// --------------
//
// Description: Shift register
//
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};
// output assignment
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
//pragma translate_off
initial begin
assert (WIDTH <= 16)
else $fatal(1, "WIDTH needs to be less than 16 because of the 16-bit LFSR");
end
//pragma translate_on
endmodule

View file

@ -0,0 +1,61 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Igor Loi - University of Bologna
// Author: Florian Zaruba, ETH Zurich
// Date: 12.11.2017
// Description: 8-bit LFSR
/// 8 bit Linear Feedback Shift register
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};
// output assignment
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
//pragma translate_off
initial begin
assert (WIDTH <= 8) else $fatal(1, "WIDTH needs to be less than 8 because of the 8-bit LFSR");
end
//pragma translate_on
endmodule

View file

@ -0,0 +1,112 @@
// Copyright (c) 2018 - 2019 ETH Zurich, University of Bologna
// All rights reserved.
//
// This code is under development and not yet released to the public.
// Until it is released, the code is under the copyright of ETH Zurich and
// the University of Bologna, and may contain confidential and/or unpublished
// work. Any reuse/redistribution is strictly forbidden without written
// permission from ETH Zurich.
//
// Bug fixes and contributions will eventually be released under the
// SolderPad open hardware license in the context of the PULP platform
// (http://www.pulp-platform.org), under the copyright of ETH Zurich and the
// University of Bologna.
/// A trailing zero counter / leading zero counter.
/// Set MODE to 0 for trailing zero counter => cnt_o is the number of trailing zeros (from the LSB)
/// Set MODE to 1 for leading zero counter => cnt_o is the number of leading zeros (from the MSB)
/// If the input does not contain a zero, `empty_o` is asserted. Additionally `cnt_o` contains
/// the maximum number of zeros - 1. For example:
/// in_i = 000_0000, empty_o = 1, cnt_o = 6 (mode = 0)
/// in_i = 000_0001, empty_o = 0, cnt_o = 0 (mode = 0)
/// in_i = 000_1000, empty_o = 0, cnt_o = 3 (mode = 0)
/// Furthermore, this unit contains a more efficient implementation for Verilator (simulation only).
/// This speeds up simulation significantly.
module lzc #(
/// The width of the input vector.
parameter int unsigned WIDTH = 2,
/// Mode selection: 0 -> trailing zero, 1 -> leading zero
parameter bit MODE = 1'b0,
/// Dependent parameter. Do **not** change!
///
/// Width of the output signal with the zero count.
parameter int unsigned CNT_WIDTH = cf_math_pkg::idx_width(WIDTH)
) (
/// Input vector to be counted.
input logic [WIDTH-1:0] in_i,
/// Count of the leading / trailing zeros.
output logic [CNT_WIDTH-1:0] cnt_o,
/// Counter is empty: Asserted if all bits in in_i are zero.
output logic empty_o
);
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);
// pragma translate_off
initial begin
assert(WIDTH > 0) else $fatal(1, "input must be at least one bit wide");
end
// pragma translate_on
logic [WIDTH-1:0][NumLevels-1:0] index_lut;
logic [2**NumLevels-1:0] sel_nodes;
logic [2**NumLevels-1:0][NumLevels-1:0] index_nodes;
logic [WIDTH-1:0] in_tmp;
// reverse vector if required
always_comb begin : flip_vector
for (int unsigned i = 0; i < WIDTH; i++) begin
in_tmp[i] = (MODE) ? in_i[WIDTH-1-i] : in_i[i];
end
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 two successive indices are still in the vector...
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 only the first index is still in the vector...
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 index is out of range
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

View file

@ -0,0 +1,77 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Up/down counter that tracks its maximum value
module max_counter #(
parameter int unsigned WIDTH = 4
) (
input logic clk_i,
input logic rst_ni,
input logic clear_i, // synchronous clear for counter
input logic clear_max_i, // synchronous clear for maximum value
input logic en_i, // enable the counter
input logic load_i, // load a new value
input logic down_i, // downcount, default is up
input logic [WIDTH-1:0] delta_i, // counter delta
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

View file

@ -0,0 +1,55 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
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
// sync reset
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

View file

@ -0,0 +1,38 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Franceco Conti <fconti@iis.ee.ethz.ch>
module onehot_to_bin #(
parameter int unsigned ONEHOT_WIDTH = 16,
// Do Not Change
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 : jl
logic [ONEHOT_WIDTH-1:0] tmp_mask;
for (genvar i = 0; i < ONEHOT_WIDTH; i++) begin : il
logic [BIN_WIDTH-1:0] tmp_i;
assign tmp_i = i;
assign tmp_mask[i] = tmp_i[j];
end
assign bin[j] = |(tmp_mask & onehot);
end
// pragma translate_off
`ifndef VERILATOR
assert final ($onehot0(onehot)) else
$fatal(1, "[onehot_to_bin] More than two bit set in the one-hot signal");
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,120 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: David Schaffenrath, TU Graz
// Author: Florian Zaruba, ETH Zurich
//
// Description: Pseudo Least Recently Used Tree (PLRU)
// See: https://en.wikipedia.org/wiki/Pseudo-LRU
module plru_tree #(
parameter int unsigned ENTRIES = 16
) (
input logic clk_i,
input logic rst_ni,
input logic [ENTRIES-1:0] used_i, // element i was used (one hot)
output logic [ENTRIES-1:0] plru_o // element i is the least recently used (one hot)
);
localparam int unsigned LogEntries = $clog2(ENTRIES);
logic [2*(ENTRIES-1)-1:0] plru_tree_q, plru_tree_d;
always_comb begin : plru_replacement
plru_tree_d = plru_tree_q;
// The PLRU-tree indexing:
// lvl0 0
// / \
// / \
// lvl1 1 2
// / \ / \
// lvl2 3 4 5 6
// / \ /\/\ /\
// ... ... ... ...
// Just predefine which nodes will be set/cleared
// E.g. for a TLB with 8 entries, the for-loop is semantically
// equivalent to the following pseudo-code:
// unique case (1'b1)
// used_i[7]: plru_tree_d[0, 2, 6] = {1, 1, 1};
// used_i[6]: plru_tree_d[0, 2, 6] = {1, 1, 0};
// used_i[5]: plru_tree_d[0, 2, 5] = {1, 0, 1};
// used_i[4]: plru_tree_d[0, 2, 5] = {1, 0, 0};
// used_i[3]: plru_tree_d[0, 1, 4] = {0, 1, 1};
// used_i[2]: plru_tree_d[0, 1, 4] = {0, 1, 0};
// used_i[1]: plru_tree_d[0, 1, 3] = {0, 0, 1};
// used_i[0]: plru_tree_d[0, 1, 3] = {0, 0, 0};
// default: begin /* No hit */ end
// endcase
for (int unsigned i = 0; i < ENTRIES; i++) begin
automatic int unsigned idx_base, shift, new_index;
// we got a hit so update the pointer as it was least recently used
if (used_i[i]) begin
// Set the nodes to the values we would expect
for (int unsigned lvl = 0; lvl < LogEntries; lvl++) begin
idx_base = $unsigned((2**lvl)-1);
// lvl0 <=> MSB, lvl1 <=> MSB-1, ...
shift = LogEntries - lvl;
// to circumvent the 32 bit integer arithmetic assignment
new_index = ~((i >> (shift-1)) & 1);
plru_tree_d[idx_base + (i >> shift)] = new_index[0];
end
end
end
// Decode tree to write enable signals
// Next for-loop basically creates the following logic for e.g. an 8 entry
// TLB (note: pseudo-code obviously):
// plru_o[7] = &plru_tree_q[ 6, 2, 0]; //plru_tree_q[0,2,6]=={1,1,1}
// plru_o[6] = &plru_tree_q[~6, 2, 0]; //plru_tree_q[0,2,6]=={1,1,0}
// plru_o[5] = &plru_tree_q[ 5,~2, 0]; //plru_tree_q[0,2,5]=={1,0,1}
// plru_o[4] = &plru_tree_q[~5,~2, 0]; //plru_tree_q[0,2,5]=={1,0,0}
// plru_o[3] = &plru_tree_q[ 4, 1,~0]; //plru_tree_q[0,1,4]=={0,1,1}
// plru_o[2] = &plru_tree_q[~4, 1,~0]; //plru_tree_q[0,1,4]=={0,1,0}
// plru_o[1] = &plru_tree_q[ 3,~1,~0]; //plru_tree_q[0,1,3]=={0,0,1}
// plru_o[0] = &plru_tree_q[~3,~1,~0]; //plru_tree_q[0,1,3]=={0,0,0}
// For each entry traverse the tree. If every tree-node matches,
// the corresponding bit of the entry's index, this is
// the next entry to replace.
for (int unsigned i = 0; i < ENTRIES; i += 1) begin
automatic logic en;
automatic int unsigned idx_base, shift, new_index;
en = 1'b1;
for (int unsigned lvl = 0; lvl < LogEntries; lvl++) begin
idx_base = $unsigned((2**lvl)-1);
// lvl0 <=> MSB, lvl1 <=> MSB-1, ...
shift = LogEntries - lvl;
// en &= plru_tree_q[idx_base + (i>>shift)] == ((i >> (shift-1)) & 1'b1);
new_index = (i >> (shift-1)) & 1;
if (new_index[0]) begin
en &= plru_tree_q[idx_base + (i>>shift)];
end else begin
en &= ~plru_tree_q[idx_base + (i>>shift)];
end
end
plru_o[i] = en;
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
// pragma translate_off
`ifndef VERILATOR
initial begin
assert (ENTRIES == 2**LogEntries) else $error("Entries must be a power of two");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,60 @@
// Copyright (C) 2013-2018 ETH Zurich, University of Bologna
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Manuel Eggimann <meggimann@iis.ee.ethz.ch>
// Description: This module calculates the hamming weight (number of ones) in
// its input vector using a balanced binary adder tree. Recursive instantiation
// is used to build the tree. Any unsigned INPUT_WIDTH larger or equal 2 is
// legal. The module pads the signal internally to the next power of two. The
// output result width is ceil(log2(INPUT_WIDTH))+1.
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
);
localparam int unsigned PaddedWidth = 1 << $clog2(INPUT_WIDTH);
logic [PaddedWidth-1:0] padded_input;
logic [PopcountWidth-2:0] left_child_result, right_child_result;
//Zero pad the input to next power of two
always_comb begin
padded_input = '0;
padded_input[INPUT_WIDTH-1:0] = data_i;
end
//Recursive instantiation to build binary adder tree
if (INPUT_WIDTH == 1) begin : single_node
assign left_child_result = 1'b0;
assign right_child_result = padded_input[0];
end else if (INPUT_WIDTH == 2) begin : leaf_node
assign left_child_result = padded_input[1];
assign right_child_result = padded_input[0];
end else begin : non_leaf_node
popcount #(.INPUT_WIDTH(PaddedWidth / 2))
left_child(
.data_i(padded_input[PaddedWidth-1:PaddedWidth/2]),
.popcount_o(left_child_result));
popcount #(.INPUT_WIDTH(PaddedWidth / 2))
right_child(
.data_i(padded_input[PaddedWidth/2-1:0]),
.popcount_o(right_child_result));
end
//Output assignment
assign popcount_o = left_child_result + right_child_result;
endmodule : popcount

View file

@ -0,0 +1,348 @@
// Copyright 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Michael Schaffner <schaffner@iis.ee.ethz.ch>, ETH Zurich
// Wolfgang Roenninger <wroennin@iis.ee.ethz.ch>, ETH Zurich
// Date: 02.04.2019
// Description: logarithmic arbitration tree with round robin arbitration scheme.
/// The rr_arb_tree employs non-starving round robin-arbitration - i.e., the priorities
/// rotate each cycle.
///
/// ## Fair vs. unfair Arbitration
///
/// This refers to fair throughput distribution when not all inputs have active requests.
/// This module has an internal state `rr_q` which defines the highest priority input. (When
/// `ExtPrio` is `1'b1` this state is provided from the outside.) The arbitration tree will
/// choose the input with the same index as currently defined by the state if it has an active
/// request. Otherwise a *random* other active input is selected. The parameter `FairArb` is used
/// to distinguish between two methods of calculating the next state.
/// * `1'b0`: The next state is calculated by advancing the current state by one. This leads to the
/// state being calculated without the context of the active request. Leading to an
/// unfair throughput distribution if not all inputs have active requests.
/// * `1'b1`: The next state jumps to the next unserved request with higher index.
/// This is achieved by using two trailing-zero-counters (`lzc`). The upper has the masked
/// `req_i` signal with all indices which will have a higher priority in the next state.
/// The trailing zero count defines the input index with the next highest priority after
/// the current one is served. When the upper is empty the lower `lzc` provides the
/// wrapped index if there are outstanding requests with lower or same priority.
/// The implication of throughput fairness on the module timing are:
/// * The trailing zero counter (`lzc`) has a loglog relation of input to output timing. This means
/// that in this module the input to register path scales with Log(Log(`NumIn`)).
/// * The `rr_arb_tree` data multiplexing scales with Log(`NumIn`). This means that the input to output
/// timing path of this module also scales scales with Log(`NumIn`).
/// This implies that in this module the input to output path is always longer than the input to
/// register path. As the output data usually also terminates in a register the parameter `FairArb`
/// only has implications on the area. When it is `1'b0` a static plus one adder is instantiated.
/// If it is `1'b1` two `lzc`, a masking logic stage and a two input multiplexer are instantiated.
/// However these are small in respect of the data multiplexers needed, as the width of the `req_i`
/// signal is usually less as than `DataWidth`.
module rr_arb_tree #(
/// Number of inputs to be arbitrated.
parameter int unsigned NumIn = 64,
/// Data width of the payload in bits. Not needed if `DataType` is overwritten.
parameter int unsigned DataWidth = 32,
/// Data type of the payload, can be overwritten with custom type. Only use of `DataWidth`.
parameter type DataType = logic [DataWidth-1:0],
/// The `ExtPrio` option allows to override the internal round robin counter via the
/// `rr_i` signal. This can be useful in case multiple arbiters need to have
/// rotating priorities that are operating in lock-step. If static priority arbitration
/// is needed, just connect `rr_i` to '0.
///
/// Set to 1'b1 to enable.
parameter bit ExtPrio = 1'b0,
/// If `AxiVldRdy` is set, the req/gnt signals are compliant with the AXI style vld/rdy
/// handshake. Namely, upstream vld (req) must not depend on rdy (gnt), as it can be deasserted
/// again even though vld is asserted. Enabling `AxiVldRdy` leads to a reduction of arbiter
/// delay and area.
///
/// Set to `1'b1` to treat req/gnt as vld/rdy.
parameter bit AxiVldRdy = 1'b0,
/// The `LockIn` option prevents the arbiter from changing the arbitration
/// decision when the arbiter is disabled. I.e., the index of the first request
/// that wins the arbitration will be locked in case the destination is not
/// able to grant the request in the same cycle.
///
/// Set to `1'b1` to enable.
parameter bit LockIn = 1'b0,
/// When set, ensures that throughput gets distributed evenly between all inputs.
///
/// Set to `1'b0` to disable.
parameter bit FairArb = 1'b1,
/// Dependent parameter, do **not** overwrite.
/// Width of the arbitration priority signal and the arbitrated index.
parameter int unsigned IdxWidth = (NumIn > 32'd1) ? unsigned'($clog2(NumIn)) : 32'd1,
/// Dependent parameter, do **not** overwrite.
/// Type for defining the arbitration priority and arbitrated index signal.
parameter type idx_t = logic [IdxWidth-1:0]
) (
/// Clock, positive edge triggered.
input logic clk_i,
/// Asynchronous reset, active low.
input logic rst_ni,
/// Clears the arbiter state. Only used if `ExtPrio` is `1'b0` or `LockIn` is `1'b1`.
input logic flush_i,
/// External round-robin priority. Only used if `ExtPrio` is `1'b1.`
input idx_t rr_i,
/// Input requests arbitration.
input logic [NumIn-1:0] req_i,
/* verilator lint_off UNOPTFLAT */
/// Input request is granted.
output logic [NumIn-1:0] gnt_o,
/* verilator lint_on UNOPTFLAT */
/// Input data for arbitration.
input DataType [NumIn-1:0] data_i,
/// Output request is valid.
output logic req_o,
/// Output request is granted.
input logic gnt_i,
/// Output data.
output DataType data_o,
/// Index from which input the data came from.
output idx_t idx_o
);
// pragma translate_off
`ifndef VERILATOR
`ifndef XSIM
// Default SVA reset
default disable iff (!rst_ni || flush_i);
`endif
`endif
// pragma translate_on
// just pass through in this corner case
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;
// non-degenerate cases
end else begin : gen_arbiter
localparam int unsigned NumLevels = unsigned'($clog2(NumIn));
/* verilator lint_off UNOPTFLAT */
idx_t [2**NumLevels-2:0] index_nodes; // used to propagate the indices
DataType [2**NumLevels-2:0] data_nodes; // used to propagate the data
logic [2**NumLevels-2:0] gnt_nodes; // used to propagate the grant to masters
logic [2**NumLevels-2:0] req_nodes; // used to propagate the requests to slave
/* lint_off */
idx_t rr_q;
logic [NumIn-1:0] req_d;
// the final arbitration decision can be taken from the root of the tree
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;
// lock arbiter decision in case we got at least one req and no acknowledge
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
// pragma translate_off
`ifndef VERILATOR
lock: assert property(
@(posedge clk_i) LockIn |-> req_o &&
(!gnt_i && !flush_i) |=> idx_o == $past(idx_o)) else
$fatal (1, "Lock implies same arbiter decision in next cycle if output is not \
ready.");
logic [NumIn-1:0] req_tmp;
assign req_tmp = req_q & req_i;
lock_req: assume property(
@(posedge clk_i) LockIn |-> lock_d |=> req_tmp == req_q) else
$fatal (1, "It is disallowed to deassert unserved request signals when LockIn is \
enabled.");
`endif
// pragma translate_on
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 ( /*unused*/ )
);
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
// this holds the highest priority
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;
// arbiter tree
for (genvar level = 0; unsigned'(level) < NumLevels; level++) begin : gen_levels
for (genvar l = 0; l < 2**level; l++) begin : gen_level
// local select signal
logic sel;
// index calcs
localparam int unsigned Idx0 = 2**level-1+l;// current node
localparam int unsigned Idx1 = 2**(level+1)-1+l*2;
//////////////////////////////////////////////////////////////
// uppermost level where data is fed in from the inputs
if (unsigned'(level) == NumLevels-1) begin : gen_first_level
// if two successive indices are still in the vector...
if (unsigned'(l) * 2 < NumIn-1) begin : gen_reduce
assign req_nodes[Idx0] = req_d[l*2] | req_d[l*2+1];
// arbitration: round robin
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 only the first index is still in the vector...
if (unsigned'(l) * 2 == NumIn-1) begin : gen_first
assign req_nodes[Idx0] = req_d[l*2];
assign index_nodes[Idx0] = '0;// always zero in this case
assign data_nodes[Idx0] = data_i[l*2];
assign gnt_o[l*2] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l*2]);
end
// if index is out of range, fill up with zeros (will get pruned)
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
//////////////////////////////////////////////////////////////
// general case for other levels within the tree
end else begin : gen_other_levels
assign req_nodes[Idx0] = req_nodes[Idx1] | req_nodes[Idx1+1];
// arbitration: round robin
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
// pragma translate_off
`ifndef VERILATOR
`ifndef XSIM
initial begin : p_assert
assert(NumIn)
else $fatal(1, "Input must be at least one element wide.");
assert(!(LockIn && ExtPrio))
else $fatal(1,"Cannot use LockIn feature together with external ExtPrio.");
end
hot_one : assert property(
@(posedge clk_i) $onehot0(gnt_o))
else $fatal (1, "Grant signal must be hot1 or zero.");
gnt0 : assert property(
@(posedge clk_i) |gnt_o |-> gnt_i)
else $fatal (1, "Grant out implies grant in.");
gnt1 : assert property(
@(posedge clk_i) req_o |-> gnt_i |-> |gnt_o)
else $fatal (1, "Req out and grant in implies grant out.");
gnt_idx : assert property(
@(posedge clk_i) req_o |-> gnt_i |-> gnt_o[idx_o])
else $fatal (1, "Idx_o / gnt_o do not match.");
req0 : assert property(
@(posedge clk_i) |req_i |-> req_o)
else $fatal (1, "Req in implies req out.");
req1 : assert property(
@(posedge clk_i) req_o |-> |req_i)
else $fatal (1, "Req out implies req in.");
`endif
`endif
// pragma translate_on
end
endmodule : rr_arb_tree

View file

@ -0,0 +1,30 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Davide Rossi <davide.rossi@unibo.it>
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

View file

@ -0,0 +1,57 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Florian Zaruba <zarubaf@iis.ee.ethz.ch>
// Description: This module is a reset synchronizer with a dedicated reset bypass pin for testmode reset.
// Pro Tip: The wise Dr. Schaffner recommends at least 4 registers!
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
);
// internal reset
logic rst_n;
logic [NumRegs-1:0] synch_regs_q;
// bypass mode
always_comb begin
if (test_mode_i == 1'b0) begin
rst_n = rst_ni;
rst_no = synch_regs_q[NumRegs-1];
init_no = synch_regs_q[NumRegs-1];
end else begin
rst_n = rst_test_mode_ni;
rst_no = rst_test_mode_ni;
init_no = 1'b1;
end
end
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
// pragma translate_off
`ifndef VERILATOR
initial begin : p_assertions
if (NumRegs < 1) $fatal(1, "At least one register is required.");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,50 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba
// Description: Deglitches a serial line by taking multiple samples until
// asserting the output high/low.
module serial_deglitch #(
parameter int unsigned SIZE = 4
)(
input logic clk_i, // clock
input logic rst_ni, // asynchronous reset active low
input logic en_i, // enable
input logic d_i, // serial data in
output logic q_o // filtered data out
);
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
// output process
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

View file

@ -0,0 +1,53 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: <zarubaf@iis.ee.ethz.ch>
//
// Description: Simple shift register for arbitrary depth and types
module shift_reg #(
parameter type dtype = logic,
parameter int unsigned Depth = 1
)(
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input dtype d_i,
output dtype d_o
);
// register of depth 0 is a wire
if (Depth == 0) begin : gen_pass_through
assign d_o = d_i;
// register of depth 1 is a simple register
end else if (Depth == 1) begin : gen_register
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
d_o <= '0;
end else begin
d_o <= d_i;
end
end
// if depth is greater than 1 it becomes a shift register
end else if (Depth > 1) begin : gen_shift_reg
dtype [Depth-1:0] reg_d, reg_q;
assign d_o = reg_q[Depth-1];
assign reg_d = {reg_q[Depth-2:0], d_i};
always_ff @(posedge clk_i or negedge rst_ni) begin
if (~rst_ni) begin
reg_q <= '0;
end else begin
reg_q <= reg_d;
end
end
end
endmodule

View file

@ -0,0 +1,46 @@
// Copyright 2018 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// Wrapper around the flushable spill register to maintain back-ward
/// compatibility.
module spill_register #(
parameter type T = logic,
parameter bit Bypass = 1'b0 // make this spill register transparent
) (
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

View file

@ -0,0 +1,105 @@
// Copyright 2021 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
/// A register with handshakes that completely cuts any combinational paths
/// between the input and output. This spill register can be flushed.
module spill_register_flushable #(
parameter type T = logic,
parameter bit Bypass = 1'b0 // make this spill register transparent
) (
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
// The A register.
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 <= '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
// The B register.
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 <= '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
// Fill the A register when the A or B register is empty. Drain the A register
// whenever it is full and being filled, or if a flush is requested.
assign a_fill = valid_i && ready_o && (!flush_i);
assign a_drain = (a_full_q && !b_full_q) || flush_i;
// Fill the B register whenever the A register is drained, but the downstream
// circuit is not ready. Drain the B register whenever it is full and the
// downstream circuit is ready, or if a flush is requested.
assign b_fill = a_drain && (!ready_i) && (!flush_i);
assign b_drain = (b_full_q && ready_i) || flush_i;
// We can accept input as long as register B is not full.
// Note: flush_i and valid_i must not be high at the same time,
// otherwise an invalid handshake may occur
assign ready_o = !a_full_q || !b_full_q;
// The unit provides output as long as one of the registers is filled.
assign valid_o = a_full_q | b_full_q;
// We empty the spill register before the slice register.
assign data_o = b_full_q ? b_data_q : a_data_q;
// pragma translate_off
`ifndef VERILATOR
flush_valid : assert property (
@(posedge clk_i) disable iff (~rst_ni) (flush_i |-> ~valid_i)) else
$warning("Trying to flush and feed the spill register simultaneously. You will lose data!");
`endif
// pragma translate_on
end
endmodule

View file

@ -0,0 +1,49 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Stream arbiter: Arbitrates a parametrizable number of input streams (i.e., valid-ready
// handshaking with dependency rules as in AXI4) to a single output stream. Once `oup_valid_o` is
// asserted, `oup_data_o` remains invariant until the output handshake has occurred. The
// arbitration scheme is round-robin with "look ahead", see the `rrarbiter` for details.
module stream_arbiter #(
parameter type DATA_T = logic, // Vivado requires a default value for type parameters.
parameter integer N_INP = -1, // Synopsys DC requires a default value for parameters.
parameter ARBITER = "rr" // "rr" or "prio"
) (
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

View file

@ -0,0 +1,82 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Stream arbiter: Arbitrates a parametrizable number of input streams (i.e., valid-ready
// handshaking with dependency rules as in AXI4) to a single output stream. Once `oup_valid_o` is
// asserted, `oup_data_o` remains invariant until the output handshake has occurred. The
// arbitration scheme is fair round-robin tree, see `rr_arb_tree` for details.
module stream_arbiter_flushable #(
parameter type DATA_T = logic, // Vivado requires a default value for type parameters.
parameter integer N_INP = -1, // Synopsys DC requires a default value for parameters.
parameter ARBITER = "rr" // "rr" or "prio"
) (
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'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 begin : gen_arb_error
// pragma translate_off
$fatal(1, "Invalid value for parameter 'ARBITER'!");
// pragma translate_on
end
endmodule

View file

@ -0,0 +1,132 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba, zarubaf@iis.ee.ethz.ch
// Description: Delay (or randomize) AXI-like handshaking
module stream_delay #(
parameter bit StallRandom = 0,
parameter int FixedDelay = 1,
parameter type payload_t = logic
)(
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 = 4;
typedef enum logic [1:0] {
Idle, Valid, Ready
} state_e;
state_e state_d, state_q;
logic load;
logic [3: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;
// Just one cycle delay
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 : /* default */;
endcase
end
if (StallRandom) begin : gen_random_stall
lfsr_16bit #(
.WIDTH ( 16 )
) 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

View file

@ -0,0 +1,36 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/// Connects the input stream (valid-ready) handshake to one of `N_OUP` output stream handshakes.
///
/// This module has no data ports because stream data does not need to be demultiplexed: the data of
/// the input stream can just be applied at all output streams.
module stream_demux #(
/// Number of connected outputs.
parameter int unsigned N_OUP = 32'd1,
/// Dependent parameters, DO NOT OVERRIDE!
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

View file

@ -0,0 +1,66 @@
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Georg Rutishauser <georgr@iis.ee.ethz.ch>
module stream_fifo #(
/// FIFO is in fall-through mode
parameter bit FALL_THROUGH = 1'b0,
/// Default data width if the fifo is of type logic
parameter int unsigned DATA_WIDTH = 32,
/// Depth can be arbitrary from 0 to 2**32
parameter int unsigned DEPTH = 8,
parameter type T = logic [DATA_WIDTH-1:0],
// DO NOT OVERWRITE THIS PARAMETER
parameter int unsigned ADDR_DEPTH = (DEPTH > 1) ? $clog2(DEPTH) : 1
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous reset active low
input logic flush_i, // flush the fifo
input logic testmode_i, // test_mode to bypass clock gating
output logic [ADDR_DEPTH-1:0] usage_o, // fill pointer
// input interface
input T data_i, // data to push into the fifo
input logic valid_i, // input data valid
output logic ready_o, // fifo is not full
// output interface
output T data_o, // output data
output logic valid_o, // fifo is not empty
input logic ready_i // pop head from fifo
);
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

View file

@ -0,0 +1,26 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Stream filter: If `drop_i` is `1`, signal `ready` to the upstream regardless of the downstream,
// and do not propagate `valid` downstream. Otherwise, connect upstream to downstream.
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

View file

@ -0,0 +1,133 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Stream fork: Connects the input stream (ready-valid) handshake to *all* of `N_OUP` output stream
// handshakes. For each input stream handshake, every output stream handshakes exactly once. The
// input stream only handshakes when all output streams have handshaked, but the output streams do
// not have to handshake simultaneously.
//
// This module has no data ports because stream data does not need to be forked: the data of the
// input stream can just be applied at all output streams.
module stream_fork #(
parameter int unsigned N_OUP = 0 // Synopsys DC requires a default value for parameters.
) (
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;
// Input control FSM
always_comb begin
// ready_o = 1'b0;
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
// If handshake on all outputs, handshake on input.
ready_o = 1'b1;
end else begin
ready_o = 1'b0;
// Otherwise, wait for inputs that did not handshake yet.
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
// Output control FSM
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 // Output handshake
if (!ready_o) begin // No input handshake yet
oup_state_d = WAIT;
end
end else begin // No output handshake
oup_ready[i] = 1'b0;
end
end
end
WAIT: begin
if (valid_i && ready_o) begin // Input handshake
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; // Synthesis fix for Vivado, which does not correctly compute the width
// of the '1 literal when assigned to a port of parametrized width.
// pragma translate_off
`ifndef VERILATOR
initial begin: p_assertions
assert (N_OUP >= 1) else $fatal(1, "Number of outputs must be at least 1!");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,95 @@
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
/// Dynamic stream fork: Connects the input stream (ready-valid) handshake to a combination of output
/// stream handshake. The combination is determined dynamically through another stream, which
/// provides a bitmask for the fork. For each input stream handshake, every output stream handshakes
/// exactly once. The input stream only handshakes when all output streams have handshaked, but the
/// output streams do not have to handshake simultaneously.
///
/// This module has no data ports because stream data does not need to be forked: the data of the
/// input stream can just be applied at all output streams.
module stream_fork_dynamic #(
/// Number of output streams
parameter int unsigned N_OUP = 32'd0 // Synopsys DC requires a default value for parameters.
) (
/// Clock
input logic clk_i,
/// Asynchronous reset, active low
input logic rst_ni,
/// Input stream valid handshake,
input logic valid_i,
/// Input stream ready handshake
output logic ready_o,
/// Selection mask for the output handshake
input logic [N_OUP-1:0] sel_i,
/// Selection mask valid
input logic sel_valid_i,
/// Selection mask ready
output logic sel_ready_o,
/// Output streams valid handshakes
output logic [N_OUP-1:0] valid_o,
/// Output streams ready handshakes
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;
// Output handshaking
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
// Input handshaking
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 )
);
// pragma translate_off
`ifndef VERILATOR
initial begin: p_assertions
assert (N_OUP >= 1) else $fatal(1, "N_OUP must be at least 1!");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,49 @@
// Copyright 2020 ETH Zurich and University of Bologna.
//
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Florian Zaruba <zarubaf@iis.ee.ethz.ch>
/// A stream interface with custom payload of type `payload_t`.
/// Handshaking rules as defined in the AXI standard.
interface STREAM_DV #(
/// Custom payload type.
parameter type payload_t = logic
)(
/// Interface clock.
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
);
/// Passive modport for scoreboard and monitors.
modport Passive (
input valid, ready, data
);
// Make sure that the handshake and payload is stable
// pragma translate_off
`ifndef VERILATOR
assert property (@(posedge clk_i) (valid && !ready |=> $stable(data)));
assert property (@(posedge clk_i) (valid && !ready |=> valid));
`endif
// pragma translate_on
endinterface

View file

@ -0,0 +1,43 @@
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
/// Stream join: Joins a parametrizable number of input streams (i.e., valid-ready handshaking with
/// dependency rules as in AXI4) to a single output stream. The output handshake happens only once
/// all inputs are valid. The data channel flows outside of this module.
module stream_join #(
/// Number of input streams
parameter int unsigned N_INP = 32'd0 // Synopsys DC requires a default value for parameters.
) (
/// Input streams valid handshakes
input logic [N_INP-1:0] inp_valid_i,
/// Input streams ready handshakes
output logic [N_INP-1:0] inp_ready_o,
/// Output stream valid handshake
output logic oup_valid_o,
/// Output stream ready handshake
input logic oup_ready_i
);
assign oup_valid_o = (&inp_valid_i);
for (genvar i = 0; i < N_INP; i++) begin : gen_inp_ready
assign inp_ready_o[i] = oup_valid_o & oup_ready_i;
end
// pragma translate_off
`ifndef VERILATOR
initial begin: p_assertions
assert (N_INP >= 1) else $fatal(1, "N_INP must be at least 1!");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,46 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/// Stream multiplexer: connects the output to one of `N_INP` data streams with valid-ready
/// handshaking.
module stream_mux #(
parameter type DATA_T = logic, // Vivado requires a default value for type parameters.
parameter integer N_INP = 0, // Synopsys DC requires a default value for value parameters.
/// Dependent parameters, DO NOT OVERRIDE!
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];
// pragma translate_off
`ifndef VERILATOR
initial begin: p_assertions
assert (N_INP >= 1) else $fatal (1, "The number of inputs must be at least 1!");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,301 @@
// Copyright (c) 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Wolfgang Roenninger <wroennin@ethz.ch>
/// Omega network using multiple `stream_xbar` as switches.
///
/// An omega network is isomorphic to a butterfly network.
///
/// Handshaking rules as defined by the `AMBA AXI` standard on default.
module stream_omega_net #(
/// Number of inputs into the network (`> 0`).
parameter int unsigned NumInp = 32'd0,
/// Number of outputs from the network (`> 0`).
parameter int unsigned NumOut = 32'd0,
/// Radix of the individual switch points of the network.
/// Currently supported are `32'd2` and `32'd4`.
parameter int unsigned Radix = 32'd2,
/// Data width of the stream. Can be overwritten by defining the type parameter `payload_t`.
parameter int unsigned DataWidth = 32'd1,
/// Payload type of the data ports, only usage of parameter `DataWidth`.
parameter type payload_t = logic [DataWidth-1:0],
/// Adds a spill register stage at each output.
parameter bit SpillReg = 1'b0,
/// Use external priority for the individual `rr_arb_trees`.
parameter int unsigned ExtPrio = 1'b0,
/// Use strict AXI valid ready handshaking.
/// To be protocol conform also the parameter `LockIn` has to be set.
parameter int unsigned AxiVldRdy = 1'b1,
/// Lock in the arbitration decision of the `rr_arb_tree`.
/// When this is set, valids have to be asserted until the corresponding transaction is indicated
/// by ready.
parameter int unsigned LockIn = 1'b1,
/// Derived parameter, do **not** overwrite!
///
/// Width of the output selection signal.
parameter int unsigned SelWidth = (NumOut > 32'd1) ? unsigned'($clog2(NumOut)) : 32'd1,
/// Derived parameter, do **not** overwrite!
///
/// Signal type definition for selecting the output at the inputs.
parameter type sel_oup_t = logic[SelWidth-1:0],
/// Derived parameter, do **not** overwrite!
///
/// Width of the input index signal.
parameter int unsigned IdxWidth = (NumInp > 32'd1) ? unsigned'($clog2(NumInp)) : 32'd1,
/// Derived parameter, do **not** overwrite!
///
/// Signal type definition indicating from which input the output came.
parameter type idx_inp_t = logic[IdxWidth-1:0]
) (
/// Clock, positive edge triggered.
input logic clk_i,
/// Asynchronous reset, active low.
input logic rst_ni,
/// Flush the state of the internal `rr_arb_tree` modules.
/// If not used set to `0`.
/// Flush should only be used if there are no active `valid_i`, otherwise it will
/// not adhere to the AXI handshaking.
input logic flush_i,
/// Provide an external state for the `rr_arb_tree` models.
/// Will only do something if ExtPrio is `1` otherwise tie to `0`.
input idx_inp_t [NumOut-1:0] rr_i,
/// Input data ports.
/// Has to be stable as long as `valid_i` is asserted when parameter `AxiVldRdy` is set.
input payload_t [NumInp-1:0] data_i,
/// Selection of the output port where the data should be routed.
/// Has to be stable as long as `valid_i` is asserted and parameter `AxiVldRdy` is set.
input sel_oup_t [NumInp-1:0] sel_i,
/// Input is valid.
input logic [NumInp-1:0] valid_i,
/// Input is ready to accept data.
output logic [NumInp-1:0] ready_o,
/// Output data ports. Valid if `valid_o = 1`
output payload_t [NumOut-1:0] data_o,
/// Index of the input port where data came from.
output idx_inp_t [NumOut-1:0] idx_o,
/// Output is valid.
output logic [NumOut-1:0] valid_o,
/// Output can be accepted.
input logic [NumOut-1:0] ready_i
);
if (NumInp <= Radix && NumOut <= Radix) begin : gen_degenerate_omega_net
// If both Number of inputs and number of outputs are smaller or the same as the radix
// just instantiate a `stream_xbar`.
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
// Find the next power of radix of either the number of inputs or number of outputs.
// This normalizes the network to a power of the radix. Unused inputs and outputs are tied off.
// If the radix is poorly chosen with respect to the number of input/outputs ports
// will lead to an explosion of tied off lanes, which will be removed during optimization.
// Can lead however to RTL simulation overhead.
// Dividing through the log base 2 of `Radix` leads to a change of base.
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))));
// Find the number of routing levels needed.
localparam int unsigned NumLevels = unsigned'(($clog2(NumLanes)+$clog2(Radix)-1)/$clog2(Radix));
// Find the number of routes per network stage. Can use a normal division here, as
// `NumLanes % Radix == 0`.
localparam int unsigned NumRouters = NumLanes / Radix;
// Define the type of sel signal to send through the network. It has to be sliced for the
// individual sel signals of a stage. This slicing has to align with `$clog2(Radix)`.
// For example `Radix = 4`, `NumOut = 17` will lead to the sel signal of an individual stage to
// be 2 bit wide, whereas signal `sel_i` of the module will be 5 bit wide.
// To prevent slicing into an undefined field the overall sel signal is then defined with
// width 6.
typedef logic [$clog2(NumLanes)-1:0] sel_dst_t;
// Selection signal type of an individual router
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;
// Define the payload which should be routed through the network.
typedef struct packed {
sel_dst_t sel_oup; // Selection of output, where it should be routed
payload_t payload; // External payload data
idx_inp_t idx_inp; // Index of the input of this packet
} omega_data_t;
// signal definitions
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;
// Generate the shuffling between the routers
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
// This parameter is from `0` to `NumLanes-1`
localparam int unsigned IdxLane = Radix * j + k;
// Do the perfect shuffle
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];
// Do the first input shuffle of layer 0.
// The inputs are connected in reverse. The reason is that then the optimization
// leaves then the biggest possible network diameter.
if (i == 0) begin : gen_shuffle_inp
// Reverse the order of the input ports
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
// Generate the `stream_xbar_routers`
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
// For the inter stage routing some bits of the overall selection are important.
// The `MSB` is for stage `0`, `MSB-1` for stage `1` and so on for the `Radix=2` case.
// For higher radices's a bit slice following the same pattern is used.
// This is the reason that the internal network is expanded to a power of two, so that
// the selection slicing always has a valid index.
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 ( /* not used */ ),
.valid_o ( out_router_valid[i][j] ),
.ready_i ( out_router_ready[i][j] )
);
end
end
// outputs are on the last level
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
// Assertions
// Make sure that the handshake and payload is stable
// pragma translate_off
`ifndef VERILATOR
default disable iff rst_ni;
for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_sel_assertions
assert property (@(posedge clk_i) (valid_i[i] |-> sel_i[i] < sel_oup_t'(NumOut))) else
$fatal(1, "Non-existing output is selected!");
end
if (AxiVldRdy) begin : gen_handshake_assertions
for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_inp_assertions
assert property (@(posedge clk_i) (valid_i[i] && !ready_o[i] |=> $stable(data_i[i]))) else
$error("data_i is unstable at input: %0d", i);
assert property (@(posedge clk_i) (valid_i[i] && !ready_o[i] |=> $stable(sel_i[i]))) else
$error("sel_i is unstable at input: %0d", i);
assert property (@(posedge clk_i) (valid_i[i] && !ready_o[i] |=> valid_i[i])) else
$error("valid_i at input %0d has been taken away without a ready.", i);
end
for (genvar i = 0; unsigned'(i) < NumOut; i++) begin : gen_out_assertions
assert property (@(posedge clk_i) (valid_o[i] && !ready_i[i] |=> $stable(data_o[i]))) else
$error("data_o is unstable at output: %0d Check that parameter LockIn is set.", i);
assert property (@(posedge clk_i) (valid_o[i] && !ready_i[i] |=> $stable(idx_o[i]))) else
$error("idx_o is unstable at output: %0d Check that parameter LockIn is set.", i);
assert property (@(posedge clk_i) (valid_o[i] && !ready_i[i] |=> valid_o[i])) else
$error("valid_o at output %0d has been taken away without a ready.", i);
end
end
initial begin : proc_parameter_assertions
assert ((2**$clog2(Radix) == Radix) && (Radix > 32'd1)) else
$fatal(1, "Radix %0d is not power of two.", Radix);
assert (2**$clog2(NumRouters) == NumRouters) else
$fatal(1, "NumRouters %0d is not power of two.", NumRouters);
assert ($clog2(NumLanes) % SelW == 0) else
$fatal(1, "Bit slicing of the internal selection signal is broken.");
end
`endif
// pragma translate_on
end
endmodule

View file

@ -0,0 +1,57 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/// Register with a simple stream-like ready/valid handshake.
/// This register does not cut combinatorial paths on all control signals; if you need a complete
/// cut, use the `spill_register`.
module stream_register #(
parameter type T = logic // Vivado requires a default value for type parameters.
) (
input logic clk_i, // Clock
input logic rst_ni, // Asynchronous active-low reset
input logic clr_i, // Synchronous clear
input logic testmode_i, // Test mode to bypass clock gating
// Input port
input logic valid_i,
output logic ready_o,
input T data_i,
// Output port
output logic valid_o,
input logic ready_i,
output T data_o
);
logic fifo_empty,
fifo_full;
fifo_v2 #(
.FALL_THROUGH (1'b0),
.DATA_WIDTH ($bits(T)),
.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),
.alm_full_o ( ),
.alm_empty_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

View file

@ -0,0 +1,134 @@
// Copyright 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Authors:
// - Andreas Kurth <akurth@iis.ee.ethz.ch>
/// `stream_to_mem`: Allows to use memories with flow control (`valid`/`ready`) for requests but without flow
/// control for output data to be used in streams.
`include "common_cells/registers.svh"
module stream_to_mem #(
/// Memory request payload type, usually write enable, write data, etc.
parameter type mem_req_t = logic,
/// Memory response payload type, usually read data
parameter type mem_resp_t = logic,
/// Number of buffered responses (fall-through, thus no additional latency). This defines the
/// maximum number of outstanding requests on the memory interface. If the attached memory
/// responds in the same cycle a request is applied, this MUST be 0. If the attached memory
/// responds at least one cycle after a request, this MUST be >= 1 and should be equal to the
/// response latency of the memory to saturate bandwidth.
parameter int unsigned BufDepth = 32'd1
) (
/// Clock
input logic clk_i,
/// Asynchronous reset, active low
input logic rst_ni,
/// Request stream interface, payload
input mem_req_t req_i,
/// Request stream interface, payload is valid for transfer
input logic req_valid_i,
/// Request stream interface, payload can be accepted
output logic req_ready_o,
/// Response stream interface, payload
output mem_resp_t resp_o,
/// Response stream interface, payload is valid for transfer
output logic resp_valid_o,
/// Response stream interface, payload can be accepted
input logic resp_ready_i,
/// Memory request interface, payload
output mem_req_t mem_req_o,
/// Memory request interface, payload is valid for transfer
output logic mem_req_valid_o,
/// Memory request interface, payload can be accepted
input logic mem_req_ready_i,
/// Memory response interface, payload
input mem_resp_t mem_resp_i,
/// Memory response interface, payload is valid
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
// Count number of outstanding requests.
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
// Can issue another request if the counter is not at its limit or a response is delivered in
// the current cycle.
assign req_ready = (cnt_q < BufDepth) | (resp_valid_o & resp_ready_i);
// Control request and memory request interface handshakes.
assign req_ready_o = mem_req_ready_i & req_ready;
assign mem_req_valid_o = req_valid_i & req_ready;
// Buffer responses.
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 ( /* unused */ )
);
// Register
`FFARN(cnt_q, cnt_d, '0, clk_i, rst_ni)
end else begin : gen_no_buf
// Control request, memory request, and response interface handshakes.
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;
// Forward responses.
assign resp_o = mem_resp_i;
end
// Forward requests.
assign mem_req_o = req_i;
// Assertions
// pragma translate_off
`ifndef VERILATOR
if (BufDepth > 0) begin : gen_buf_asserts
assert property (@(posedge clk_i) mem_resp_valid_i |-> buf_ready)
else $error("Memory response lost!");
assert property (@(posedge clk_i) cnt_q == '0 |=> cnt_q != '1)
else $error("Counter underflowed!");
assert property (@(posedge clk_i) cnt_q == BufDepth |=> cnt_q != BufDepth + 1)
else $error("Counter overflowed!");
end else begin : gen_no_buf_asserts
assume property (@(posedge clk_i) mem_req_valid_o & mem_req_ready_i |-> mem_resp_valid_i)
else $error("Without BufDepth = 0, the memory must respond in the same cycle!");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,198 @@
// Copyright (c) 2020 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Wolfgang Roenninger <wroennin@ethz.ch>
/// Fully connected stream crossbar.
///
/// Handshaking rules as defined by the `AMBA AXI` standard on default.
module stream_xbar #(
/// Number of inputs into the crossbar (`> 0`).
parameter int unsigned NumInp = 32'd0,
/// Number of outputs from the crossbar (`> 0`).
parameter int unsigned NumOut = 32'd0,
/// Data width of the stream. Can be overwritten by defining the type parameter `payload_t`.
parameter int unsigned DataWidth = 32'd1,
/// Payload type of the data ports, only usage of parameter `DataWidth`.
parameter type payload_t = logic [DataWidth-1:0],
/// Adds a spill register stage at each output.
parameter bit OutSpillReg = 1'b0,
/// Use external priority for the individual `rr_arb_trees`.
parameter int unsigned ExtPrio = 1'b0,
/// Use strict AXI valid ready handshaking.
/// To be protocol conform also the parameter `LockIn` has to be set.
parameter int unsigned AxiVldRdy = 1'b1,
/// Lock in the arbitration decision of the `rr_arb_tree`.
/// When this is set, valids have to be asserted until the corresponding transaction is indicated
/// by ready.
parameter int unsigned LockIn = 1'b1,
/// Derived parameter, do **not** overwrite!
///
/// Width of the output selection signal.
parameter int unsigned SelWidth = (NumOut > 32'd1) ? unsigned'($clog2(NumOut)) : 32'd1,
/// Derived parameter, do **not** overwrite!
///
/// Signal type definition for selecting the output at the inputs.
parameter type sel_oup_t = logic[SelWidth-1:0],
/// Derived parameter, do **not** overwrite!
///
/// Width of the input index signal.
parameter int unsigned IdxWidth = (NumInp > 32'd1) ? unsigned'($clog2(NumInp)) : 32'd1,
/// Derived parameter, do **not** overwrite!
///
/// Signal type definition indicating from which input the output came.
parameter type idx_inp_t = logic[IdxWidth-1:0]
) (
/// Clock, positive edge triggered.
input logic clk_i,
/// Asynchronous reset, active low.
input logic rst_ni,
/// Flush the state of the internal `rr_arb_tree` modules.
/// If not used set to `0`.
/// Flush should only be used if there are no active `valid_i`, otherwise it will
/// not adhere to the AXI handshaking.
input logic flush_i,
/// Provide an external state for the `rr_arb_tree` models.
/// Will only do something if ExtPrio is `1` otherwise tie to `0`.
input idx_inp_t [NumOut-1:0] rr_i,
/// Input data ports.
/// Has to be stable as long as `valid_i` is asserted when parameter `AxiVldRdy` is set.
input payload_t [NumInp-1:0] data_i,
/// Selection of the output port where the data should be routed.
/// Has to be stable as long as `valid_i` is asserted and parameter `AxiVldRdy` is set.
input sel_oup_t [NumInp-1:0] sel_i,
/// Input is valid.
input logic [NumInp-1:0] valid_i,
/// Input is ready to accept data.
output logic [NumInp-1:0] ready_o,
/// Output data ports. Valid if `valid_o = 1`
output payload_t [NumOut-1:0] data_o,
/// Index of the input port where data came from.
output idx_inp_t [NumOut-1:0] idx_o,
/// Output is valid.
output logic [NumOut-1:0] valid_o,
/// Output can be accepted.
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;
// Generate the input selection
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] )
);
// Do the switching cross of the signals.
for (genvar j = 0; unsigned'(j) < NumOut; j++) begin : gen_cross
// Propagate the data from this input to all outputs.
assign out_data[j][i] = data_i[i];
// switch handshaking
assign out_valid[j][i] = inp_valid[i][j];
assign inp_ready[i][j] = out_ready[j][i];
end
end
// Generate the output arbitration.
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 )
);
// Assign the outputs (deaggregate the data).
assign data_o[j] = spill.data;
assign idx_o[j] = spill.idx;
end
// Assertions
// Make sure that the handshake and payload is stable
// pragma translate_off
`ifndef VERILATOR
default disable iff rst_ni;
for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_sel_assertions
assert property (@(posedge clk_i) (valid_i[i] |-> sel_i[i] < sel_oup_t'(NumOut))) else
$fatal(1, "Non-existing output is selected!");
end
if (AxiVldRdy) begin : gen_handshake_assertions
for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_inp_assertions
assert property (@(posedge clk_i) (valid_i[i] && !ready_o[i] |=> $stable(data_i[i]))) else
$error("data_i is unstable at input: %0d", i);
assert property (@(posedge clk_i) (valid_i[i] && !ready_o[i] |=> $stable(sel_i[i]))) else
$error("sel_i is unstable at input: %0d", i);
assert property (@(posedge clk_i) (valid_i[i] && !ready_o[i] |=> valid_i[i])) else
$error("valid_i at input %0d has been taken away without a ready.", i);
end
for (genvar i = 0; unsigned'(i) < NumOut; i++) begin : gen_out_assertions
assert property (@(posedge clk_i) (valid_o[i] && !ready_i[i] |=> $stable(data_o[i]))) else
$error("data_o is unstable at output: %0d Check that parameter LockIn is set.", i);
assert property (@(posedge clk_i) (valid_o[i] && !ready_i[i] |=> $stable(idx_o[i]))) else
$error("idx_o is unstable at output: %0d Check that parameter LockIn is set.", i);
assert property (@(posedge clk_i) (valid_o[i] && !ready_i[i] |=> valid_o[i])) else
$error("valid_o at output %0d has been taken away without a ready.", i);
end
end
initial begin : proc_parameter_assertions
assert (NumInp > 32'd0) else $fatal(1, "NumInp has to be > 0!");
assert (NumOut > 32'd0) else $fatal(1, "NumOut has to be > 0!");
end
`endif
// pragma translate_on
endmodule

View file

@ -0,0 +1,173 @@
// Copyright (c) 2019 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Author: Wolfgang Roenninger <wroennin@ethz.ch>
// This module implements a fully parameterizable substitution-permutation hash
// function. The hash is structured in stages consisting of a shuffle of the input bits
// and then xoring for each bit 3 pseudo-random bits of the shuffeled vector.
// The hash function is NOT cryptographically secure!
// From the keys it computes a sequence of pseudo-random numbers, which determine the permutations
// and substitutions. As pseudo random generator a multiplicative linear congruential
// generator is used and uses different constants for the computation of the permutation
// and substitution respectively.
// The permutation shuffles the bits using a variant of the Fisher-Yates shuffle algorithm.
// The substitution per stage is the xor of 3 pseudo random bits of the previous stage.
// As shifting and xoring of a signal do not change its distribution, the distribution
// of the output hash is the same as the one of the input data.
//
// Parameters:
// - `InpWidth`: The input width of the vector `data_i`.
// - `HashWidth`: The output width of the substitution-permutation hash.
// - `NoRounds`: The amount of permutation, substitution stages generated. Translates
// into how many levels of xor's there will be before optimization.
// - `PermuteKey`: The Key for the pseudo-random generator used for determining the exact
// permutation (shuffled wiring between each xor stage) at compile/elaboration.
// Any `int unsigned` value can be used as key, however one should examine the
// output of the hash function.
// - `XorKey`: The Key for the pseudo-random generator used for determining the xor
// of bits between stages. The same principles as for `PermuteKey` applies,
// however one should look that both keys have a greatest common divisor of 1.
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
) (
// is purely combinational
input logic [InpWidth-1:0] data_i,
output logic [HashWidth-1:0] hash_o,
output logic [2**HashWidth-1:0] hash_onehot_o
);
// typedefs and respective localparams
typedef int unsigned perm_lists_t [NoRounds][InpWidth];
localparam perm_lists_t PERMUTATIONS = get_permutations(PermuteKey);
// encoding for inner most array:
// position 0 indicates the number of inputs, 2 or 3
// the other positions 1 - 3 indicate the inputs
typedef int unsigned xor_stages_t [NoRounds][InpWidth][3];
localparam xor_stages_t XorStages = get_xor_stages(XorKey);
// stage signals
logic [NoRounds-1:0][InpWidth-1:0] permuted, xored;
// for each round
for (genvar r = 0; r < NoRounds; r++) begin : gen_round
// for each bit
for (genvar i = 0; i < InpWidth ; i++) begin : gen_sub_per
// assign the permutation
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 the xor substitution
assign xored[r][i] = permuted[r][XorStages[r][i][0]] ^
permuted[r][XorStages[r][i][1]] ^
permuted[r][XorStages[r][i][2]];
end
end
// output assignment, take the bottom bits of the last round
assign hash_o = xored[NoRounds-1][HashWidth-1:0];
// for onehot run trough a decoder
assign hash_onehot_o = 1 << hash_o;
// PRG is MLCG (multiplicative linear congruential generator)
// Constant values the same as RtlUniform from Native API
// X(n+1) = (a*X(n)+c) mod m
// a: large prime
// c: increment
// m: range
// Shuffling is a variation of the Fisher-Yates shuffle algorithm
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;
// do it for each round
for (int unsigned r = 0; r < NoRounds; r++) begin
// initialize the index array
for (int unsigned i = 0; i < InpWidth; i++) begin
indices[r][i] = i;
end
// do the shuffling
for (int unsigned i = 0; i < InpWidth; i++) begin
// get the 'random' number
if (i > 0) begin
rand_number = (A * rand_number + C) % M;
index = rand_number % i;
end
// do the shuffling
if (i != index) begin
perm_array[r][i] = perm_array[r][index];
perm_array[r][index] = indices[r][i];
end
end
// advance the PRG a bit
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
// PRG is MLCG (multiplicative linear congruential generator)
// Constant values the same as Numerical Recipes
// X(n+1) = (a*X(n)+c) mod m
// a: large prime
// c: increment
// m: range
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;
// int unsigned even = 0;
longint unsigned advance = 0;
longint unsigned rand_number = (A * seed + C) % M;
// fill the array with 'randon' inputs
// for each xor, a even random number is two input, uneven is tree
// for each round
for (int unsigned r = 0; r < NoRounds; r++) begin
// for each bit
for (int unsigned i = 0; i < InpWidth; i++) begin
rand_number = (A * rand_number + C) % M;
// even = rand_number[3];
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
// advance the PRG a bit
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

View file

@ -0,0 +1,35 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Antonio Pullini <pullinia@iis.ee.ethz.ch>
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
);
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

View file

@ -0,0 +1,56 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// Antonio Pullini <pullinia@iis.ee.ethz.ch>
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

View file

@ -0,0 +1,21 @@
// Copyright 2018 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//
// Author: Florian Zaruba, ETH Zurich
// Date: 29.10.2018
// Description: Dummy circuit to mitigate Open Pin warnings
/* verilator lint_off UNUSED */
module unread (
input logic d_i
);
endmodule
/* verilator lint_on UNUSED */

3
vendor/pulp-platform/fpnew/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
*~
html
Bender.lock

176
vendor/pulp-platform/fpnew/LICENSE vendored Normal file
View file

@ -0,0 +1,176 @@
SOLDERPAD HARDWARE LICENSE version 0.51
This license is based closely on the Apache License Version 2.0, but is not
approved or endorsed by the Apache Foundation. A copy of the non-modified
Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0.
As this license is not currently OSI or FSF approved, the Licensor permits any
Work licensed under this License, at the option of the Licensee, to be treated
as licensed under the Apache License Version 2.0 (which is so approved).
This License is licensed under the terms of this License and in particular
clause 7 below (Disclaimer of Warranties) applies in relation to its use.
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the Rights owner or entity authorized by the Rights owner
that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Rights” means copyright and any similar right including design right (whether
registered or unregistered), semiconductor topography (mask) rights and
database rights (but excluding Patents and Trademarks).
“Source” form shall mean the preferred form for making modifications, including
but not limited to source code, net lists, board layouts, CAD files,
documentation source, and configuration files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object
code, generated documentation, the instantiation of a hardware design and
conversions to other media types, including intermediate forms such as
bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask
works).
“Work” shall mean the work of authorship, whether in Source form or other
Object form, made available under the License, as indicated by a Rights notice
that is included in or attached to the work (an example is provided in the
Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) or physically connect to or interoperate with the interfaces of, the Work
and Derivative Works thereof.
“Contribution” shall mean any design or work of authorship, including the
original version of the Work and any modifications or additions to that Work or
Derivative Works thereof, that is intentionally submitted to Licensor for
inclusion in the Work by the Rights owner or by an individual or Legal Entity
authorized to submit on behalf of the Rights owner. For the purposes of this
definition, “submitted” means any form of electronic, verbal, or written
communication sent to the Licensor or its representatives, including but not
limited to communication on electronic mailing lists, source code control
systems, and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but excluding
communication that is conspicuously marked or otherwise designated in writing
by the Rights owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of License. Subject to the terms and conditions of this License, each
Contributor hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable license under the Rights to reproduce,
prepare Derivative Works of, publicly display, publicly perform, sublicense,
and distribute the Work and such Derivative Works in Source or Object form and
do anything in relation to the Work as if the Rights did not exist.
3. Grant of Patent License. Subject to the terms and conditions of this
License, each Contributor hereby grants to You a perpetual, worldwide,
non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this
section) patent license to make, have made, use, offer to sell, sell, import,
and otherwise transfer the Work, where such license applies only to those
patent claims licensable by such Contributor that are necessarily infringed by
their Contribution(s) alone or by combination of their Contribution(s) with the
Work to which such Contribution(s) was submitted. If You institute patent
litigation against any entity (including a cross-claim or counterclaim in a
lawsuit) alleging that the Work or a Contribution incorporated within the Work
constitutes direct or contributory patent infringement, then any patent
licenses granted to You under this License for that Work shall terminate as of
the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or
Derivative Works thereof in any medium, with or without modifications, and in
Source or Object form, provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy
of this License; and
You must cause any modified files to carry prominent notices stating that
You changed the files; and
You must retain, in the Source form of any Derivative Works that You
distribute, all copyright, patent, trademark, and attribution notices from
the Source form of the Work, excluding those notices that do not pertain to
any part of the Derivative Works; and
If the Work includes a “NOTICE” text file as part of its distribution, then
any Derivative Works that You distribute must include a readable copy of
the attribution notices contained within such NOTICE file, excluding those
notices that do not pertain to any part of the Derivative Works, in at
least one of the following places: within a NOTICE text file distributed as
part of the Derivative Works; within the Source form or documentation, if
provided along with the Derivative Works; or, within a display generated by
the Derivative Works, if and wherever such third-party notices normally
appear. The contents of the NOTICE file are for informational purposes only
and do not modify the License. You may add Your own attribution notices
within Derivative Works that You distribute, alongside or as an addendum to
the NOTICE text from the Work, provided that such additional attribution
notices cannot be construed as modifying the License. You may add Your own
copyright statement to Your modifications and may provide additional or
different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a
whole, provided Your use, reproduction, and distribution of the Work
otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any
Contribution intentionally submitted for inclusion in the Work by You to the
Licensor shall be under the terms and conditions of this License, without any
additional terms or conditions. Notwithstanding the above, nothing herein shall
supersede or modify the terms of any separate license agreement you may have
executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names,
trademarks, service marks, or product names of the Licensor, except as required
for reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in
writing, Licensor provides the Work (and each Contributor provides its
Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied, including, without limitation, any warranties
or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any risks
associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in
tort (including negligence), contract, or otherwise, unless required by
applicable law (such as deliberate and grossly negligent acts) or agreed to in
writing, shall any Contributor be liable to You for damages, including any
direct, indirect, special, incidental, or consequential damages of any
character arising as a result of this License or out of the use or inability to
use the Work (including but not limited to damages for loss of goodwill, work
stoppage, computer failure or malfunction, or any and all other commercial
damages or losses), even if such Contributor has been advised of the
possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or
Derivative Works thereof, You may choose to offer, and charge a fee for,
acceptance of support, warranty, indemnity, or other liability obligations
and/or rights consistent with this License. However, in accepting such
obligations, You may act only on Your own behalf and on Your sole
responsibility, not on behalf of any other Contributor, and only if You agree
to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

147
vendor/pulp-platform/fpnew/README.md vendored Normal file
View file

@ -0,0 +1,147 @@
# FPnew - New Floating-Point Unit with Transprecision Capabilities
Parametric floating-point unit with support for standard RISC-V formats and operations as well as transprecision formats, written in SystemVerilog.
Maintainer: Stefan Mach <smach@iis.ee.ethz.ch>
## Features
The FPU is a parametric design that allows generating FP hardware units for various use cases.
Even though mainly designed for use in RISC-V processors, the FPU or its sub-blocks can easily be utilized in other environments.
Our design aims to be compliant with IEEE 754-2008 and provides the following features:
### Formats
Any IEEE 754-2008 style binary floating-point format can be supported, including single-, double-, quad- and half-precision (`binary32`, `binary64`, `binary128`, `binary16`).
Formats can be defined with arbitrary number of exponent and mantissa bits through parameters and are always symmetrically biased.
Multiple FP formats can be supported concurrently, and the number of formats supported is not limited.
Multiple integer formats with arbitrary number of bits (as source or destionation of conversions) can also be defined.
### Operations
- Addition/Subtraction
- Multiplication
- Fused multiply-add in four flavours (`fmadd`, `fmsub`, `fnmadd`, `fnmsub`)
- Division<sup>1</sup>
- Square root<sup>1</sup>
- Minimum/Maximum<sup>2</sup>
- Comparisons
- Sign-Injections (`copy`, `abs`, `negate`, `copySign` etc.)
- Conversions among all supported FP formats
- Conversions between FP formats and integers (signed & unsigned) and vice versa
- Classification
Multi-format FMA operations (i.e. multiplication in one format, accumulation in another) are optionally supported.
Optionally, *packed-SIMD* versions of all the above operations can be generated for formats narrower than the FPU datapath width.
E.g.: Support for double-precision (64bit) operations and two simultaneous single-precision (32bit) operations.
It is also possible to generate only a subset of operations if e.g. divisions are not needed.
<sup>1</sup>Some compliance issues with IEEE 754-2008 are currently known to exist<br>
<sup>2</sup>Implementing IEEE 754-201x `minimumNumber` and `maximumNumber`, respectively
### Rounding modes
All IEEE 754-2008 rounding modes are supported, namely
- `roundTiesToEven`
- `roundTiesToAway`
- `roundTowardPositive`
- `roundTowardNegative`
- `roundTowardZero`
### Status Flags
All IEEE 754-2008 status flags are supported, namely
- Invalid operation (`NV`)
- Division by zero (`DZ`)
- Overflow (`OF`)
- Underflow (`UF`)
- Inexact (`NX`)
## Getting Started
### Dependencies
FPnew currently depends on the following:
- `lzc` and `rr_arb_tree` from the `common_cells` repository (https://github.com/pulp-platform/common_cells.git)
- optional: Divider and square-root unit from the `fpu-div-sqrt-mvp` repository (https://github.com/pulp-platform/fpu_div_sqrt_mvp.git)
These two repositories are included in the source code directory as git submodules, use
```bash
git submodule update --init --recursive
```
if you want to load these dependencies there.
Consider using [Bender](https://github.com/fabianschuiki/bender.git) for managing dependencies in your projects. FPnew comes with Bender support!
### Usage
The top-level module of the FPU is called `fpnew_top` and can be directly instantiated in your design.
Make sure you compile the package `fpnew_pkg` ahead of any files making references to types, parameters or functions defined there.
It is discouraged to `import` all of `fpnew_pkg` into your source files. Instead, explicitly scope references into the package like so: `fpnew_pkg::foo`.
#### Example Instantiation
```SystemVerilog
// FPU instance
fpnew_top #(
.Features ( fpnew_pkg::RV64D ),
.Implementation ( fpnew_pkg::DEFAULT_NOREGS ),
.TagType ( logic )
) i_fpnew_top (
.clk_i,
.rst_ni,
.operands_i,
.rnd_mode_i,
.op_i,
.op_mod_i,
.src_fmt_i,
.dst_fmt_i,
.int_fmt_i,
.vectorial_op_i,
.tag_i,
.in_valid_i,
.in_ready_o,
.flush_i,
.result_o,
.status_o,
.tag_o,
.out_valid_o,
.out_ready_i,
.busy_o
);
```
### Documentation
More in-depth documentation on the FPnew configuration, interfaces and architecture is provided in [`docs/README.md`](docs/README.md).
### Issues and Contributing
In case you find any issues with FPnew that have not been reported yet, don't hesitate to open a new [issue](https://github.com/pulp-platform/fpnew/issues) here on Github.
Please, don't use the issue tracker for support questions.
Instead, consider contacting the maintainers or consulting the [PULP forums](https://pulp-platform.org/community/index.php).
In case you would like to contribute to the project, please refer to the contributing guidelines in [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) before opening a pull request.
### Repository Structure
HDL source code can be found in the `src` directory while documentation is located in `docs`.
A changelog is kept at [`docs/CHANGELOG.md`](docs/CHANGELOG.md).
This repository loosely follows the [GitFlow](https://nvie.com/posts/a-successful-git-branching-model/) branching model.
This means that the `master` branch is considered stable and used to publish releases of the FPU while the `develop` branch contains features and bugfixes that have not yet been properly released.
Furthermore, this repository tries to adhere to [SemVer](https://semver.org/), as outlined in the [changelog](docs/CHANGELOG.md).
## Licensing
FPnew is released under the *SolderPad Hardware License*, which is a permissive license based on Apache 2.0. Please refer to the [license file](LICENSE) for further information.
## Acknowledgement
This project has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreement No 732631.
For further information, visit [oprecomp.eu](http://oprecomp.eu).
![OPRECOMP](docs/fig/oprecomp_logo_inline1.png)

Some files were not shown because too many files have changed in this diff Show more