fpu: ⬆️ Update FPU version (#1102)

Co-authored-by: Matteo Perotti <mperotti@iis.ee.ethz.ch>
Co-authored-by: Matheus Cavalcante <matheusd@iis.ee.ethz.ch>
Co-authored-by: JeanRochCoulon <jean-roch.coulon@thalesgroup.com>
This commit is contained in:
Nils Wistoff 2023-04-14 23:53:45 +02:00 committed by GitHub
parent c1df1da568
commit 3833439fb7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
97 changed files with 415 additions and 5812 deletions

View file

@ -10,7 +10,7 @@ dependencies:
axi: { git: "https://github.com/pulp-platform/axi.git", version: 0.31.0 }
common_cells:
{ git: "https://github.com/pulp-platform/common_cells", version: 1.23.0 }
fpnew: { git: "https://github.com/pulp-platform/fpnew.git", version: 0.6.2 }
fpnew: { git: "https://github.com/openhwgroup/cvfpu.git", version: 0.7.0 }
tech_cells_generic:
{
git: "https://github.com/pulp-platform/tech_cells_generic.git",
@ -103,25 +103,25 @@ sources:
# - vendor/pulp-platform/common_cells/src/delta_counter.sv
# Floating point unit
# - vendor/pulp-platform/fpnew/src/fpnew_pkg.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
# - 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_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/openhwgroup/cvfpu/src/fpnew_pkg.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_cast_multi.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_classifier.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_divsqrt_multi.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_fma_multi.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_fma.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_noncomp.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_opgroup_block.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_opgroup_fmt_slice.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_opgroup_multifmt_slice.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_rounding.sv
# - vendor/openhwgroup/cvfpu/src/fpnew_top.sv
# - vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
# - vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
# - vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
# - vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
# - vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
# - vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
# - vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
# Top-level source files (not necessarily instantiated at the top of the cva6).
- core/ariane.sv

View file

@ -28,7 +28,7 @@ vendor/pulp-platform/axi/src/axi_pkg.sv
core/include/ariane_axi_pkg.sv
core/include/wt_cache_pkg.sv
core/include/axi_intf.sv
vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
vendor/openhwgroup/cvfpu/src/fpnew_pkg.sv
core/include/cvxif_pkg.sv
vendor/pulp-platform/common_cells/src/cf_math_pkg.sv
core/include/instr_tracer_pkg.sv
@ -132,25 +132,25 @@ 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
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
vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_mvp_wrapper.sv
vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/preprocess_mvp.sv
vendor/openhwgroup/cvfpu/src/fpnew_cast_multi.sv
vendor/openhwgroup/cvfpu/src/fpnew_classifier.sv
vendor/openhwgroup/cvfpu/src/fpnew_divsqrt_multi.sv
vendor/openhwgroup/cvfpu/src/fpnew_fma_multi.sv
vendor/openhwgroup/cvfpu/src/fpnew_fma.sv
vendor/openhwgroup/cvfpu/src/fpnew_noncomp.sv
vendor/openhwgroup/cvfpu/src/fpnew_opgroup_block.sv
vendor/openhwgroup/cvfpu/src/fpnew_opgroup_fmt_slice.sv
vendor/openhwgroup/cvfpu/src/fpnew_opgroup_multifmt_slice.sv
vendor/openhwgroup/cvfpu/src/fpnew_rounding.sv
vendor/openhwgroup/cvfpu/src/fpnew_top.sv
core/pmp/src/pmp.sv
core/pmp/src/pmp_entry.sv
common/local/util/instr_tracer.sv

View file

@ -77,25 +77,25 @@ ${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}/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
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_pkg.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_cast_multi.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_classifier.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_divsqrt_multi.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_fma_multi.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_fma.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_noncomp.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_opgroup_block.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_opgroup_fmt_slice.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_opgroup_multifmt_slice.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_rounding.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpnew_top.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/defs_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/control_mvp.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/div_sqrt_top_mvp.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/iteration_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/norm_div_sqrt_mvp.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/src/fpu_div_sqrt_mvp/hdl/nrbd_nrsc_mvp.sv
${CVA6_REPO_DIR}/vendor/openhwgroup/cvfpu/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/cva6.sv

View file

@ -525,6 +525,7 @@ module fpu_wrap import ariane_pkg::*; (
.int_fmt_i ( fpnew_pkg::int_format_e'(fpu_ifmt) ),
.vectorial_op_i ( fpu_vec_op ),
.tag_i ( fpu_tag ),
.simd_mask_i ( 1'b1 ),
.in_valid_i ( fpu_in_valid ),
.in_ready_o ( fpu_in_ready ),
.flush_i,

View file

@ -12,7 +12,7 @@
../../axi/src/axi_pkg.sv
../../axi/src/axi_intf.sv
../../axi/src/axi_test.sv
../../../vendor/pulp-platform/fpnew/src/fpnew_pkg.sv
../../../vendor/openhwgroup/cvfpu/src/fpnew_pkg.sv
../../../core/include/ariane_pkg.sv
../ariane_soc_pkg.sv
../ariane_axi_soc_pkg.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 "../../vendor/pulp-platform/fpnew/src/common_cells/include/ $search_path"
set_app_var search_path "../../vendor/pulp-platform/common_cells/include/ $search_path"
sh rm -rf work
sh mkdir work

33
vendor/openhwgroup/cvfpu/CITATION.cff vendored Normal file
View file

@ -0,0 +1,33 @@
cff-version: 1.2.0
message: "If you use FPnew, please cite it as below."
authors:
- family-names: "Mach"
given-names: "Stefan"
orcid: "https://orcid.org/0000-0002-3476-8857"
title: "FPnew: - New Floating-Point Unit with Transprecision Capabilities"
version: 0.6.6
url: "https://github.com/pulp-platform/fpnew"
preferred-citation:
type: article
authors:
- family-names: "Mach"
given-names: "Stefan"
orcid: "https://orcid.org/0000-0002-3476-8857"
- family-names: "Schuiki"
given-names: "Fabian"
orcid: "https://orcid.org/0000-0002-9923-5031"
- family-names: "Zaruba"
given-names: "Florian"
orcid: "https://orcid.org/0000-0002-8194-6521"
- family-names: "Benini"
given-names: "Luca"
orcid: "https://orcid.org/0000-0001-8068-3806"
doi: "10.1109/TVLSI.2020.3044752"
journal: "IEEE Transactions on Very Large Scale Integration (VLSI) Systems"
month: 12
start: 774
end: 787
title: "FPnew: An Open-Source Multiformat Floating-Point Unit Architecture for Energy-Proportional Transprecision Computing"
issue: 4
volume: 29
year: 2020

View file

@ -2,7 +2,8 @@
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>
Maintainer: Luca Bertaccini <lbertaccini@iis.ee.ethz.ch>
Principal Author: Stefan Mach <smach@iis.ee.ethz.ch>
## Features
@ -138,6 +139,32 @@ Furthermore, this repository tries to adhere to [SemVer](https://semver.org/), a
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.
## Publication
If you use FPnew in your work, you can cite us:
<details>
<summary>FPnew Publication</summary>
<p>
```
@article{mach2020fpnew,
title={Fpnew: An open-source multiformat floating-point unit architecture for energy-proportional transprecision computing},
author={Mach, Stefan and Schuiki, Fabian and Zaruba, Florian and Benini, Luca},
journal={IEEE Transactions on Very Large Scale Integration (VLSI) Systems},
volume={29},
number={4},
pages={774--787},
year={2020},
publisher={IEEE}
}
```
</p>
</details>
## Acknowledgement
This project has received funding from the European Union's Horizon 2020 research and innovation programme under grant agreement No 732631.

View file

@ -8,6 +8,8 @@
// 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>
@ -38,6 +40,7 @@ module fpnew_cast_multi #(
input fpnew_pkg::fp_format_e dst_fmt_i,
input fpnew_pkg::int_format_e int_fmt_i,
input TagType tag_i,
input logic mask_i,
input AuxType aux_i,
// Input Handshake
input logic in_valid_i,
@ -48,6 +51,7 @@ module fpnew_cast_multi #(
output fpnew_pkg::status_t status_o,
output logic extension_bit_o,
output TagType tag_o,
output logic mask_o,
output AuxType aux_o,
// Output handshake
output logic out_valid_o,
@ -114,6 +118,7 @@ module fpnew_cast_multi #(
fpnew_pkg::fp_format_e [0:NUM_INP_REGS] inp_pipe_dst_fmt_q;
fpnew_pkg::int_format_e [0:NUM_INP_REGS] inp_pipe_int_fmt_q;
TagType [0:NUM_INP_REGS] inp_pipe_tag_q;
logic [0:NUM_INP_REGS] inp_pipe_mask_q;
AuxType [0:NUM_INP_REGS] inp_pipe_aux_q;
logic [0:NUM_INP_REGS] inp_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -129,6 +134,7 @@ module fpnew_cast_multi #(
assign inp_pipe_dst_fmt_q[0] = dst_fmt_i;
assign inp_pipe_int_fmt_q[0] = int_fmt_i;
assign inp_pipe_tag_q[0] = tag_i;
assign inp_pipe_mask_q[0] = mask_i;
assign inp_pipe_aux_q[0] = aux_i;
assign inp_pipe_valid_q[0] = in_valid_i;
// Input stage: Propagate pipeline ready signal to updtream circuitry
@ -155,6 +161,7 @@ module fpnew_cast_multi #(
`FFL(inp_pipe_dst_fmt_q[i+1], inp_pipe_dst_fmt_q[i], reg_ena, fpnew_pkg::fp_format_e'(0))
`FFL(inp_pipe_int_fmt_q[i+1], inp_pipe_int_fmt_q[i], reg_ena, fpnew_pkg::int_format_e'(0))
`FFL(inp_pipe_tag_q[i+1], inp_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(inp_pipe_mask_q[i+1], inp_pipe_mask_q[i], reg_ena, '0)
`FFL(inp_pipe_aux_q[i+1], inp_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: assign selected pipe outputs to signals for later use
@ -328,6 +335,7 @@ module fpnew_cast_multi #(
fpnew_pkg::fp_format_e [0:NUM_MID_REGS] mid_pipe_dst_fmt_q;
fpnew_pkg::int_format_e [0:NUM_MID_REGS] mid_pipe_int_fmt_q;
TagType [0:NUM_MID_REGS] mid_pipe_tag_q;
logic [0:NUM_MID_REGS] mid_pipe_mask_q;
AuxType [0:NUM_MID_REGS] mid_pipe_aux_q;
logic [0:NUM_MID_REGS] mid_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -348,6 +356,7 @@ module fpnew_cast_multi #(
assign mid_pipe_dst_fmt_q[0] = dst_fmt_q;
assign mid_pipe_int_fmt_q[0] = int_fmt_q;
assign mid_pipe_tag_q[0] = inp_pipe_tag_q[NUM_INP_REGS];
assign mid_pipe_mask_q[0] = inp_pipe_mask_q[NUM_INP_REGS];
assign mid_pipe_aux_q[0] = inp_pipe_aux_q[NUM_INP_REGS];
assign mid_pipe_valid_q[0] = inp_pipe_valid_q[NUM_INP_REGS];
// Input stage: Propagate pipeline ready signal to input pipe
@ -380,6 +389,7 @@ module fpnew_cast_multi #(
`FFL(mid_pipe_dst_fmt_q[i+1], mid_pipe_dst_fmt_q[i], reg_ena, fpnew_pkg::fp_format_e'(0))
`FFL(mid_pipe_int_fmt_q[i+1], mid_pipe_int_fmt_q[i], reg_ena, fpnew_pkg::int_format_e'(0))
`FFL(mid_pipe_tag_q[i+1], mid_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(mid_pipe_mask_q[i+1], mid_pipe_mask_q[i], reg_ena, '0)
`FFL(mid_pipe_aux_q[i+1], mid_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: assign selected pipe outputs to signals for later use
@ -489,6 +499,7 @@ module fpnew_cast_multi #(
logic [NUM_FORMATS-1:0] fmt_uf_after_round;
logic [NUM_INT_FORMATS-1:0][WIDTH-1:0] ifmt_pre_round_abs; // per format
logic [NUM_INT_FORMATS-1:0] ifmt_of_after_round;
logic rounded_sign;
logic [WIDTH-1:0] rounded_abs; // absolute value of result after rounding
@ -573,14 +584,33 @@ module fpnew_cast_multi #(
end
end
// Classification after rounding select by destination format
assign uf_after_round = fmt_uf_after_round[dst_fmt_q2];
assign of_after_round = fmt_of_after_round[dst_fmt_q2];
// Negative integer result needs to be brought into two's complement
assign rounded_int_res = rounded_sign ? unsigned'(-rounded_abs) : rounded_abs;
assign rounded_int_res_zero = (rounded_int_res == '0);
// Detect integer overflows after rounding (only positives)
for (genvar ifmt = 0; ifmt < int'(NUM_INT_FORMATS); ifmt++) begin : gen_int_overflow
// Set up some constants
localparam int unsigned INT_WIDTH = fpnew_pkg::int_width(fpnew_pkg::int_format_e'(ifmt));
if (IntFmtConfig[ifmt]) begin : active_format
always_comb begin : detect_overflow
ifmt_of_after_round[ifmt] = 1'b0;
// Int result can overflow if we're at the max exponent
if (!rounded_sign && input_exp_q == signed'(INT_WIDTH - 2 + op_mod_q2)) begin
// Check whether the rounded MSB differs from unrounded MSB
ifmt_of_after_round[ifmt] = ~rounded_int_res[INT_WIDTH-2+op_mod_q2];
end
end
end else begin : inactive_format
assign ifmt_of_after_round[ifmt] = fpnew_pkg::DONT_CARE;
end
end
// Classification after rounding select by destination format
assign uf_after_round = fmt_uf_after_round[dst_fmt_q2];
assign of_after_round = dst_is_int_q ? ifmt_of_after_round[int_fmt_q2] : fmt_of_after_round[dst_fmt_q2];
// -------------------------
// FP Special case handling
// -------------------------
@ -664,7 +694,7 @@ module fpnew_cast_multi #(
// Detect special case from source format (inf, nan, overflow, nan-boxing or negative unsigned)
assign int_result_is_special = info_q.is_nan | info_q.is_inf |
of_before_round | ~info_q.is_boxed |
of_before_round | of_after_round | ~info_q.is_boxed |
(input_sign_q & op_mod_q2 & ~rounded_int_res_zero);
// All integer special cases are invalid
@ -714,6 +744,7 @@ module fpnew_cast_multi #(
fpnew_pkg::status_t [0:NUM_OUT_REGS] out_pipe_status_q;
logic [0:NUM_OUT_REGS] out_pipe_ext_bit_q;
TagType [0:NUM_OUT_REGS] out_pipe_tag_q;
logic [0:NUM_OUT_REGS] out_pipe_mask_q;
AuxType [0:NUM_OUT_REGS] out_pipe_aux_q;
logic [0:NUM_OUT_REGS] out_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -724,6 +755,7 @@ module fpnew_cast_multi #(
assign out_pipe_status_q[0] = status_d;
assign out_pipe_ext_bit_q[0] = extension_bit;
assign out_pipe_tag_q[0] = mid_pipe_tag_q[NUM_MID_REGS];
assign out_pipe_mask_q[0] = mid_pipe_mask_q[NUM_MID_REGS];
assign out_pipe_aux_q[0] = mid_pipe_aux_q[NUM_MID_REGS];
assign out_pipe_valid_q[0] = mid_pipe_valid_q[NUM_MID_REGS];
// Input stage: Propagate pipeline ready signal to inside pipe
@ -745,6 +777,7 @@ module fpnew_cast_multi #(
`FFL(out_pipe_status_q[i+1], out_pipe_status_q[i], reg_ena, '0)
`FFL(out_pipe_ext_bit_q[i+1], out_pipe_ext_bit_q[i], reg_ena, '0)
`FFL(out_pipe_tag_q[i+1], out_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(out_pipe_mask_q[i+1], out_pipe_mask_q[i], reg_ena, '0)
`FFL(out_pipe_aux_q[i+1], out_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: Ready travels backwards from output side, driven by downstream circuitry
@ -754,6 +787,7 @@ module fpnew_cast_multi #(
assign status_o = out_pipe_status_q[NUM_OUT_REGS];
assign extension_bit_o = out_pipe_ext_bit_q[NUM_OUT_REGS];
assign tag_o = out_pipe_tag_q[NUM_OUT_REGS];
assign mask_o = out_pipe_mask_q[NUM_OUT_REGS];
assign aux_o = out_pipe_aux_q[NUM_OUT_REGS];
assign out_valid_o = out_pipe_valid_q[NUM_OUT_REGS];
assign busy_o = (| {inp_pipe_valid_q, mid_pipe_valid_q, out_pipe_valid_q});

View file

@ -8,6 +8,8 @@
// 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>

View file

@ -8,6 +8,8 @@
// 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>
@ -33,16 +35,22 @@ module fpnew_divsqrt_multi #(
input fpnew_pkg::operation_e op_i,
input fpnew_pkg::fp_format_e dst_fmt_i,
input TagType tag_i,
input logic mask_i,
input AuxType aux_i,
// Input Handshake
input logic in_valid_i,
output logic in_ready_o,
output logic divsqrt_done_o,
input logic simd_synch_done_i,
output logic divsqrt_ready_o,
input logic simd_synch_rdy_i,
input logic flush_i,
// Output signals
output logic [WIDTH-1:0] result_o,
output fpnew_pkg::status_t status_o,
output logic extension_bit_o,
output TagType tag_o,
output logic mask_o,
output AuxType aux_o,
// Output handshake
output logic out_valid_o,
@ -82,6 +90,7 @@ module fpnew_divsqrt_multi #(
fpnew_pkg::operation_e [0:NUM_INP_REGS] inp_pipe_op_q;
fpnew_pkg::fp_format_e [0:NUM_INP_REGS] inp_pipe_dst_fmt_q;
TagType [0:NUM_INP_REGS] inp_pipe_tag_q;
logic [0:NUM_INP_REGS] inp_pipe_mask_q;
AuxType [0:NUM_INP_REGS] inp_pipe_aux_q;
logic [0:NUM_INP_REGS] inp_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -93,6 +102,7 @@ module fpnew_divsqrt_multi #(
assign inp_pipe_op_q[0] = op_i;
assign inp_pipe_dst_fmt_q[0] = dst_fmt_i;
assign inp_pipe_tag_q[0] = tag_i;
assign inp_pipe_mask_q[0] = mask_i;
assign inp_pipe_aux_q[0] = aux_i;
assign inp_pipe_valid_q[0] = in_valid_i;
// Input stage: Propagate pipeline ready signal to updtream circuitry
@ -115,6 +125,7 @@ module fpnew_divsqrt_multi #(
`FFL(inp_pipe_op_q[i+1], inp_pipe_op_q[i], reg_ena, fpnew_pkg::FMADD)
`FFL(inp_pipe_dst_fmt_q[i+1], inp_pipe_dst_fmt_q[i], reg_ena, fpnew_pkg::fp_format_e'(0))
`FFL(inp_pipe_tag_q[i+1], inp_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(inp_pipe_mask_q[i+1], inp_pipe_mask_q[i], reg_ena, '0)
`FFL(inp_pipe_aux_q[i+1], inp_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: assign selected pipe outputs to signals for later use
@ -152,20 +163,29 @@ module fpnew_divsqrt_multi #(
// ------------
// Control FSM
// ------------
logic in_ready; // input handshake with upstream
logic div_valid, sqrt_valid; // input signalling with unit
logic unit_ready, unit_done; // status signals from unit instance
logic unit_ready, unit_done, unit_done_q; // status signals from unit instance
logic op_starting; // high in the cycle a new operation starts
logic out_valid, out_ready; // output handshake with downstream
logic hold_result; // whether to put result into hold register
logic data_is_held; // data in hold register is valid
logic unit_busy; // valid data in flight
// FSM states
typedef enum logic [1:0] {IDLE, BUSY, HOLD} fsm_state_e;
fsm_state_e state_q, state_d;
// Upstream ready comes from sanitization FSM
assign inp_pipe_ready[NUM_INP_REGS] = in_ready;
// Ready synch with other lanes
// Bring the FSM-generated ready outside the unit, to synchronize it with the other lanes
assign divsqrt_ready_o = in_ready;
// Upstream ready comes from sanitization FSM, and it is synched among all the lanes
assign inp_pipe_ready[NUM_INP_REGS] = simd_synch_rdy_i;
// Valid synch with other lanes
// When one divsqrt unit completes an operation, keep its done high, waiting for the other lanes
// As soon as all the lanes are over, we can clear this FF and start with a new operation
`FFLARNC(unit_done_q, unit_done, unit_done, simd_synch_done_i, 1'b0, clk_i, rst_ni);
// Tell the other units that this unit has finished now or in the past
assign divsqrt_done_o = unit_done_q | unit_done;
// Valids are gated by the FSM ready. Invalid input ops run a sqrt to not lose illegal instr.
assign div_valid = in_valid_q & (op_q == fpnew_pkg::DIV) & in_ready & ~flush_i;
@ -177,8 +197,6 @@ module fpnew_divsqrt_multi #(
// Default assignments
in_ready = 1'b0;
out_valid = 1'b0;
hold_result = 1'b0;
data_is_held = 1'b0;
unit_busy = 1'b0;
state_d = state_q;
@ -193,8 +211,8 @@ module fpnew_divsqrt_multi #(
// Operation in progress
BUSY: begin
unit_busy = 1'b1; // data in flight
// If the unit is done with processing
if (unit_done) begin
// If all the lanes are done with processing
if (simd_synch_done_i) begin
out_valid = 1'b1; // try to commit result downstream
// If downstream accepts our result
if (out_ready) begin
@ -205,7 +223,6 @@ module fpnew_divsqrt_multi #(
end
// Otherwise if downstream is not ready for the result
end else begin
hold_result = 1'b1; // activate the hold register
state_d = HOLD; // wait for the pipeline to take the data
end
end
@ -213,7 +230,6 @@ module fpnew_divsqrt_multi #(
// Waiting with valid result for downstream
HOLD: begin
unit_busy = 1'b1; // data in flight
data_is_held = 1'b1; // data in hold register is valid
out_valid = 1'b1; // try to commit result downstream
// If the result is accepted by downstream
if (out_ready) begin
@ -242,11 +258,13 @@ module fpnew_divsqrt_multi #(
// Hold additional information while the operation is in progress
logic result_is_fp8_q;
TagType result_tag_q;
logic result_mask_q;
AuxType result_aux_q;
// Fill the registers everytime a valid operation arrives (load FF, active low asynch rst)
`FFL(result_is_fp8_q, input_is_fp8, op_starting, '0)
`FFL(result_tag_q, inp_pipe_tag_q[NUM_INP_REGS], op_starting, '0)
`FFL(result_mask_q, inp_pipe_mask_q[NUM_INP_REGS],op_starting, '0)
`FFL(result_aux_q, inp_pipe_aux_q[NUM_INP_REGS], op_starting, '0)
// -----------------
@ -255,6 +273,7 @@ module fpnew_divsqrt_multi #(
logic [63:0] unit_result;
logic [WIDTH-1:0] adjusted_result, held_result_q;
fpnew_pkg::status_t unit_status, held_status_q;
logic hold_en;
div_sqrt_top_mvp i_divsqrt_lei (
.Clk_CI ( clk_i ),
@ -276,9 +295,12 @@ module fpnew_divsqrt_multi #(
// Adjust result width and fix FP8
assign adjusted_result = result_is_fp8_q ? unit_result >> 8 : unit_result;
// Hold the result when one lane has finished execution, except when all the lanes finish together
// and the result can be accepted downstream
assign hold_en = unit_done & (~simd_synch_done_i | ~out_ready);
// The Hold register (load, no reset)
`FFLNR(held_result_q, adjusted_result, hold_result, clk_i)
`FFLNR(held_status_q, unit_status, hold_result, clk_i)
`FFLNR(held_result_q, adjusted_result, hold_en, clk_i)
`FFLNR(held_status_q, unit_status, hold_en, clk_i)
// --------------
// Output Select
@ -286,8 +308,8 @@ module fpnew_divsqrt_multi #(
logic [WIDTH-1:0] result_d;
fpnew_pkg::status_t status_d;
// Prioritize hold register data
assign result_d = data_is_held ? held_result_q : adjusted_result;
assign status_d = data_is_held ? held_status_q : unit_status;
assign result_d = unit_done_q ? held_result_q : adjusted_result;
assign status_d = unit_done_q ? held_status_q : unit_status;
// ----------------
// Output Pipeline
@ -296,6 +318,7 @@ module fpnew_divsqrt_multi #(
logic [0:NUM_OUT_REGS][WIDTH-1:0] out_pipe_result_q;
fpnew_pkg::status_t [0:NUM_OUT_REGS] out_pipe_status_q;
TagType [0:NUM_OUT_REGS] out_pipe_tag_q;
logic [0:NUM_OUT_REGS] out_pipe_mask_q;
AuxType [0:NUM_OUT_REGS] out_pipe_aux_q;
logic [0:NUM_OUT_REGS] out_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -305,6 +328,7 @@ module fpnew_divsqrt_multi #(
assign out_pipe_result_q[0] = result_d;
assign out_pipe_status_q[0] = status_d;
assign out_pipe_tag_q[0] = result_tag_q;
assign out_pipe_mask_q[0] = result_mask_q;
assign out_pipe_aux_q[0] = result_aux_q;
assign out_pipe_valid_q[0] = out_valid;
// Input stage: Propagate pipeline ready signal to inside pipe
@ -325,6 +349,7 @@ module fpnew_divsqrt_multi #(
`FFL(out_pipe_result_q[i+1], out_pipe_result_q[i], reg_ena, '0)
`FFL(out_pipe_status_q[i+1], out_pipe_status_q[i], reg_ena, '0)
`FFL(out_pipe_tag_q[i+1], out_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(out_pipe_mask_q[i+1], out_pipe_mask_q[i], reg_ena, '0)
`FFL(out_pipe_aux_q[i+1], out_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: Ready travels backwards from output side, driven by downstream circuitry
@ -334,6 +359,7 @@ module fpnew_divsqrt_multi #(
assign status_o = out_pipe_status_q[NUM_OUT_REGS];
assign extension_bit_o = 1'b1; // always NaN-Box result
assign tag_o = out_pipe_tag_q[NUM_OUT_REGS];
assign mask_o = out_pipe_mask_q[NUM_OUT_REGS];
assign aux_o = out_pipe_aux_q[NUM_OUT_REGS];
assign out_valid_o = out_pipe_valid_q[NUM_OUT_REGS];
assign busy_o = (| {inp_pipe_valid_q, unit_busy, out_pipe_valid_q});

View file

@ -8,6 +8,8 @@
// 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>
@ -31,6 +33,7 @@ module fpnew_fma #(
input fpnew_pkg::operation_e op_i,
input logic op_mod_i,
input TagType tag_i,
input logic mask_i,
input AuxType aux_i,
// Input Handshake
input logic in_valid_i,
@ -41,6 +44,7 @@ module fpnew_fma #(
output fpnew_pkg::status_t status_o,
output logic extension_bit_o,
output TagType tag_o,
output logic mask_o,
output AuxType aux_o,
// Output handshake
output logic out_valid_o,
@ -64,8 +68,8 @@ module fpnew_fma #(
// datapath leakage. This is either given by the exponent bits or the width of the LZC result.
// In most reasonable FP formats the internal exponent will be wider than the LZC result.
localparam int unsigned EXP_WIDTH = unsigned'(fpnew_pkg::maximum(EXP_BITS + 2, LZC_RESULT_WIDTH));
// Shift amount width: maximum internal mantissa size is 3p+3 bits
localparam int unsigned SHIFT_AMOUNT_WIDTH = $clog2(3 * PRECISION_BITS + 3);
// Shift amount width: maximum internal mantissa size is 3p+4 bits
localparam int unsigned SHIFT_AMOUNT_WIDTH = $clog2(3 * PRECISION_BITS + 5);
// Pipelines
localparam NUM_INP_REGS = PipeConfig == fpnew_pkg::BEFORE
? NumPipeRegs
@ -102,6 +106,7 @@ module fpnew_fma #(
fpnew_pkg::operation_e [0:NUM_INP_REGS] inp_pipe_op_q;
logic [0:NUM_INP_REGS] inp_pipe_op_mod_q;
TagType [0:NUM_INP_REGS] inp_pipe_tag_q;
logic [0:NUM_INP_REGS] inp_pipe_mask_q;
AuxType [0:NUM_INP_REGS] inp_pipe_aux_q;
logic [0:NUM_INP_REGS] inp_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -114,6 +119,7 @@ module fpnew_fma #(
assign inp_pipe_op_q[0] = op_i;
assign inp_pipe_op_mod_q[0] = op_mod_i;
assign inp_pipe_tag_q[0] = tag_i;
assign inp_pipe_mask_q[0] = mask_i;
assign inp_pipe_aux_q[0] = aux_i;
assign inp_pipe_valid_q[0] = in_valid_i;
// Input stage: Propagate pipeline ready signal to updtream circuitry
@ -137,6 +143,7 @@ module fpnew_fma #(
`FFL(inp_pipe_op_q[i+1], inp_pipe_op_q[i], reg_ena, fpnew_pkg::FMADD)
`FFL(inp_pipe_op_mod_q[i+1], inp_pipe_op_mod_q[i], reg_ena, '0)
`FFL(inp_pipe_tag_q[i+1], inp_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(inp_pipe_mask_q[i+1], inp_pipe_mask_q[i], reg_ena, '0)
`FFL(inp_pipe_aux_q[i+1], inp_pipe_aux_q[i], reg_ena, AuxType'('0))
end
@ -167,7 +174,7 @@ module fpnew_fma #(
// | FNMSUB | \c 1 | FNMADD: Invert sign of operands A and C
// | ADD | \c 0 | ADD: Set operand A to +1.0
// | ADD | \c 1 | SUB: Set operand A to +1.0, invert sign of operand C
// | MUL | \c 0 | MUL: Set operand C to +0.0
// | MUL | \c 0 | MUL: Set operand C to +0.0 or -0.0 depending on the rounding mode
// | *others* | \c - | *invalid*
// \note \c op_mod_q always inverts the sign of the addend.
always_comb begin : op_select
@ -190,8 +197,11 @@ module fpnew_fma #(
operand_a = '{sign: 1'b0, exponent: BIAS, mantissa: '0};
info_a = '{is_normal: 1'b1, is_boxed: 1'b1, default: 1'b0}; //normal, boxed value.
end
fpnew_pkg::MUL: begin // Set addend to -0 (for proper rounding with RDN)
operand_c = '{sign: 1'b1, exponent: '0, mantissa: '0};
fpnew_pkg::MUL: begin // Set addend to +0 or -0, depending whether the rounding mode is RDN
if (inp_pipe_rnd_mode_q[NUM_INP_REGS] == fpnew_pkg::RDN)
operand_c = '{sign: 1'b0, exponent: '0, mantissa: '0};
else
operand_c = '{sign: 1'b1, exponent: '0, mantissa: '0};
info_c = '{is_zero: 1'b1, is_boxed: 1'b1, default: 1'b0}; //zero, boxed value.
end
default: begin // propagate don't cares
@ -403,6 +413,7 @@ module fpnew_fma #(
fp_t [0:NUM_MID_REGS] mid_pipe_spec_res_q;
fpnew_pkg::status_t [0:NUM_MID_REGS] mid_pipe_spec_stat_q;
TagType [0:NUM_MID_REGS] mid_pipe_tag_q;
logic [0:NUM_MID_REGS] mid_pipe_mask_q;
AuxType [0:NUM_MID_REGS] mid_pipe_aux_q;
logic [0:NUM_MID_REGS] mid_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -422,6 +433,7 @@ module fpnew_fma #(
assign mid_pipe_spec_res_q[0] = special_result;
assign mid_pipe_spec_stat_q[0] = special_status;
assign mid_pipe_tag_q[0] = inp_pipe_tag_q[NUM_INP_REGS];
assign mid_pipe_mask_q[0] = inp_pipe_mask_q[NUM_INP_REGS];
assign mid_pipe_aux_q[0] = inp_pipe_aux_q[NUM_INP_REGS];
assign mid_pipe_valid_q[0] = inp_pipe_valid_q[NUM_INP_REGS];
// Input stage: Propagate pipeline ready signal to input pipe
@ -453,6 +465,7 @@ module fpnew_fma #(
`FFL(mid_pipe_spec_res_q[i+1], mid_pipe_spec_res_q[i], reg_ena, '0)
`FFL(mid_pipe_spec_stat_q[i+1], mid_pipe_spec_stat_q[i], reg_ena, '0)
`FFL(mid_pipe_tag_q[i+1], mid_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(mid_pipe_mask_q[i+1], mid_pipe_mask_q[i], reg_ena, '0)
`FFL(mid_pipe_aux_q[i+1], mid_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: assign selected pipe outputs to signals for later use
@ -629,6 +642,7 @@ module fpnew_fma #(
fp_t [0:NUM_OUT_REGS] out_pipe_result_q;
fpnew_pkg::status_t [0:NUM_OUT_REGS] out_pipe_status_q;
TagType [0:NUM_OUT_REGS] out_pipe_tag_q;
logic [0:NUM_OUT_REGS] out_pipe_mask_q;
AuxType [0:NUM_OUT_REGS] out_pipe_aux_q;
logic [0:NUM_OUT_REGS] out_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -638,6 +652,7 @@ module fpnew_fma #(
assign out_pipe_result_q[0] = result_d;
assign out_pipe_status_q[0] = status_d;
assign out_pipe_tag_q[0] = mid_pipe_tag_q[NUM_MID_REGS];
assign out_pipe_mask_q[0] = mid_pipe_mask_q[NUM_MID_REGS];
assign out_pipe_aux_q[0] = mid_pipe_aux_q[NUM_MID_REGS];
assign out_pipe_valid_q[0] = mid_pipe_valid_q[NUM_MID_REGS];
// Input stage: Propagate pipeline ready signal to inside pipe
@ -658,6 +673,7 @@ module fpnew_fma #(
`FFL(out_pipe_result_q[i+1], out_pipe_result_q[i], reg_ena, '0)
`FFL(out_pipe_status_q[i+1], out_pipe_status_q[i], reg_ena, '0)
`FFL(out_pipe_tag_q[i+1], out_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(out_pipe_mask_q[i+1], out_pipe_mask_q[i], reg_ena, '0)
`FFL(out_pipe_aux_q[i+1], out_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: Ready travels backwards from output side, driven by downstream circuitry
@ -667,6 +683,7 @@ module fpnew_fma #(
assign status_o = out_pipe_status_q[NUM_OUT_REGS];
assign extension_bit_o = 1'b1; // always NaN-Box result
assign tag_o = out_pipe_tag_q[NUM_OUT_REGS];
assign mask_o = out_pipe_mask_q[NUM_OUT_REGS];
assign aux_o = out_pipe_aux_q[NUM_OUT_REGS];
assign out_valid_o = out_pipe_valid_q[NUM_OUT_REGS];
assign busy_o = (| {inp_pipe_valid_q, mid_pipe_valid_q, out_pipe_valid_q});

View file

@ -8,6 +8,8 @@
// 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>
@ -34,6 +36,7 @@ module fpnew_fma_multi #(
input fpnew_pkg::fp_format_e src_fmt_i, // format of the multiplicands
input fpnew_pkg::fp_format_e dst_fmt_i, // format of the addend and result
input TagType tag_i,
input logic mask_i,
input AuxType aux_i,
// Input Handshake
input logic in_valid_i,
@ -44,6 +47,7 @@ module fpnew_fma_multi #(
output fpnew_pkg::status_t status_o,
output logic extension_bit_o,
output TagType tag_o,
output logic mask_o,
output AuxType aux_o,
// Output handshake
output logic out_valid_o,
@ -70,8 +74,8 @@ module fpnew_fma_multi #(
// datapath leakage. This is either given by the exponent bits or the width of the LZC result.
// In most reasonable FP formats the internal exponent will be wider than the LZC result.
localparam int unsigned EXP_WIDTH = fpnew_pkg::maximum(SUPER_EXP_BITS + 2, LZC_RESULT_WIDTH);
// Shift amount width: maximum internal mantissa size is 3p+3 bits
localparam int unsigned SHIFT_AMOUNT_WIDTH = $clog2(3 * PRECISION_BITS + 3);
// Shift amount width: maximum internal mantissa size is 3p+4 bits
localparam int unsigned SHIFT_AMOUNT_WIDTH = $clog2(3 * PRECISION_BITS + 5);
// Pipelines
localparam NUM_INP_REGS = PipeConfig == fpnew_pkg::BEFORE
? NumPipeRegs
@ -115,6 +119,7 @@ module fpnew_fma_multi #(
fpnew_pkg::fp_format_e [0:NUM_INP_REGS] inp_pipe_src_fmt_q;
fpnew_pkg::fp_format_e [0:NUM_INP_REGS] inp_pipe_dst_fmt_q;
TagType [0:NUM_INP_REGS] inp_pipe_tag_q;
logic [0:NUM_INP_REGS] inp_pipe_mask_q;
AuxType [0:NUM_INP_REGS] inp_pipe_aux_q;
logic [0:NUM_INP_REGS] inp_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -129,6 +134,7 @@ module fpnew_fma_multi #(
assign inp_pipe_src_fmt_q[0] = src_fmt_i;
assign inp_pipe_dst_fmt_q[0] = dst_fmt_i;
assign inp_pipe_tag_q[0] = tag_i;
assign inp_pipe_mask_q[0] = mask_i;
assign inp_pipe_aux_q[0] = aux_i;
assign inp_pipe_valid_q[0] = in_valid_i;
// Input stage: Propagate pipeline ready signal to updtream circuitry
@ -154,6 +160,7 @@ module fpnew_fma_multi #(
`FFL(inp_pipe_src_fmt_q[i+1], inp_pipe_src_fmt_q[i], reg_ena, fpnew_pkg::fp_format_e'(0))
`FFL(inp_pipe_dst_fmt_q[i+1], inp_pipe_dst_fmt_q[i], reg_ena, fpnew_pkg::fp_format_e'(0))
`FFL(inp_pipe_tag_q[i+1], inp_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(inp_pipe_mask_q[i+1], inp_pipe_mask_q[i], reg_ena, '0)
`FFL(inp_pipe_aux_q[i+1], inp_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: assign selected pipe outputs to signals for later use
@ -216,7 +223,7 @@ module fpnew_fma_multi #(
// | FNMSUB | \c 1 | FNMADD: Invert sign of operands A and C
// | ADD | \c 0 | ADD: Set operand A to +1.0
// | ADD | \c 1 | SUB: Set operand A to +1.0, invert sign of operand C
// | MUL | \c 0 | MUL: Set operand C to +0.0
// | MUL | \c 0 | MUL: Set operand C to +0.0 or -0.0 depending on the rounding mode
// | *others* | \c - | *invalid*
// \note \c op_mod_q always inverts the sign of the addend.
always_comb begin : op_select
@ -239,8 +246,11 @@ module fpnew_fma_multi #(
operand_a = '{sign: 1'b0, exponent: fpnew_pkg::bias(src_fmt_q), mantissa: '0};
info_a = '{is_normal: 1'b1, is_boxed: 1'b1, default: 1'b0}; //normal, boxed value.
end
fpnew_pkg::MUL: begin // Set addend to -0 (for proper rounding with RDN)
operand_c = '{sign: 1'b1, exponent: '0, mantissa: '0};
fpnew_pkg::MUL: begin // Set addend to +0 or -0, depending whether the rounding mode is RDN
if (inp_pipe_rnd_mode_q[NUM_INP_REGS] == fpnew_pkg::RDN)
operand_c = '{sign: 1'b0, exponent: '0, mantissa: '0};
else
operand_c = '{sign: 1'b1, exponent: '0, mantissa: '0};
info_c = '{is_zero: 1'b1, is_boxed: 1'b1, default: 1'b0}; //zero, boxed value.
end
default: begin // propagate don't cares
@ -336,6 +346,8 @@ module fpnew_fma_multi #(
end
end else begin : inactive_format
assign fmt_special_result[fmt] = '{default: fpnew_pkg::DONT_CARE};
assign fmt_special_status[fmt] = '0;
assign fmt_result_is_special[fmt] = 1'b0;
end
end
@ -486,6 +498,7 @@ module fpnew_fma_multi #(
fp_t [0:NUM_MID_REGS] mid_pipe_spec_res_q;
fpnew_pkg::status_t [0:NUM_MID_REGS] mid_pipe_spec_stat_q;
TagType [0:NUM_MID_REGS] mid_pipe_tag_q;
logic [0:NUM_MID_REGS] mid_pipe_mask_q;
AuxType [0:NUM_MID_REGS] mid_pipe_aux_q;
logic [0:NUM_MID_REGS] mid_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -506,6 +519,7 @@ module fpnew_fma_multi #(
assign mid_pipe_spec_res_q[0] = special_result;
assign mid_pipe_spec_stat_q[0] = special_status;
assign mid_pipe_tag_q[0] = inp_pipe_tag_q[NUM_INP_REGS];
assign mid_pipe_mask_q[0] = inp_pipe_mask_q[NUM_INP_REGS];
assign mid_pipe_aux_q[0] = inp_pipe_aux_q[NUM_INP_REGS];
assign mid_pipe_valid_q[0] = inp_pipe_valid_q[NUM_INP_REGS];
// Input stage: Propagate pipeline ready signal to input pipe
@ -538,6 +552,7 @@ module fpnew_fma_multi #(
`FFL(mid_pipe_spec_res_q[i+1], mid_pipe_spec_res_q[i], reg_ena, '0)
`FFL(mid_pipe_spec_stat_q[i+1], mid_pipe_spec_stat_q[i], reg_ena, '0)
`FFL(mid_pipe_tag_q[i+1], mid_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(mid_pipe_mask_q[i+1], mid_pipe_mask_q[i], reg_ena, '0)
`FFL(mid_pipe_aux_q[i+1], mid_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: assign selected pipe outputs to signals for later use
@ -776,6 +791,7 @@ module fpnew_fma_multi #(
logic [0:NUM_OUT_REGS][WIDTH-1:0] out_pipe_result_q;
fpnew_pkg::status_t [0:NUM_OUT_REGS] out_pipe_status_q;
TagType [0:NUM_OUT_REGS] out_pipe_tag_q;
logic [0:NUM_OUT_REGS] out_pipe_mask_q;
AuxType [0:NUM_OUT_REGS] out_pipe_aux_q;
logic [0:NUM_OUT_REGS] out_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -785,6 +801,7 @@ module fpnew_fma_multi #(
assign out_pipe_result_q[0] = result_d;
assign out_pipe_status_q[0] = status_d;
assign out_pipe_tag_q[0] = mid_pipe_tag_q[NUM_MID_REGS];
assign out_pipe_mask_q[0] = mid_pipe_mask_q[NUM_MID_REGS];
assign out_pipe_aux_q[0] = mid_pipe_aux_q[NUM_MID_REGS];
assign out_pipe_valid_q[0] = mid_pipe_valid_q[NUM_MID_REGS];
// Input stage: Propagate pipeline ready signal to inside pipe
@ -805,6 +822,7 @@ module fpnew_fma_multi #(
`FFL(out_pipe_result_q[i+1], out_pipe_result_q[i], reg_ena, '0)
`FFL(out_pipe_status_q[i+1], out_pipe_status_q[i], reg_ena, '0)
`FFL(out_pipe_tag_q[i+1], out_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(out_pipe_mask_q[i+1], out_pipe_mask_q[i], reg_ena, '0)
`FFL(out_pipe_aux_q[i+1], out_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: Ready travels backwards from output side, driven by downstream circuitry
@ -814,6 +832,7 @@ module fpnew_fma_multi #(
assign status_o = out_pipe_status_q[NUM_OUT_REGS];
assign extension_bit_o = 1'b1; // always NaN-Box result
assign tag_o = out_pipe_tag_q[NUM_OUT_REGS];
assign mask_o = out_pipe_mask_q[NUM_OUT_REGS];
assign aux_o = out_pipe_aux_q[NUM_OUT_REGS];
assign out_valid_o = out_pipe_valid_q[NUM_OUT_REGS];
assign busy_o = (| {inp_pipe_valid_q, mid_pipe_valid_q, out_pipe_valid_q});

View file

@ -8,6 +8,8 @@
// 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>
@ -31,6 +33,7 @@ module fpnew_noncomp #(
input fpnew_pkg::operation_e op_i,
input logic op_mod_i,
input TagType tag_i,
input logic mask_i,
input AuxType aux_i,
// Input Handshake
input logic in_valid_i,
@ -43,6 +46,7 @@ module fpnew_noncomp #(
output fpnew_pkg::classmask_e class_mask_o,
output logic is_class_o,
output TagType tag_o,
output logic mask_o,
output AuxType aux_o,
// Output handshake
output logic out_valid_o,
@ -87,6 +91,7 @@ module fpnew_noncomp #(
fpnew_pkg::operation_e [0:NUM_INP_REGS] inp_pipe_op_q;
logic [0:NUM_INP_REGS] inp_pipe_op_mod_q;
TagType [0:NUM_INP_REGS] inp_pipe_tag_q;
logic [0:NUM_INP_REGS] inp_pipe_mask_q;
AuxType [0:NUM_INP_REGS] inp_pipe_aux_q;
logic [0:NUM_INP_REGS] inp_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -99,6 +104,7 @@ module fpnew_noncomp #(
assign inp_pipe_op_q[0] = op_i;
assign inp_pipe_op_mod_q[0] = op_mod_i;
assign inp_pipe_tag_q[0] = tag_i;
assign inp_pipe_mask_q[0] = mask_i;
assign inp_pipe_aux_q[0] = aux_i;
assign inp_pipe_valid_q[0] = in_valid_i;
// Input stage: Propagate pipeline ready signal to updtream circuitry
@ -122,6 +128,7 @@ module fpnew_noncomp #(
`FFL(inp_pipe_op_q[i+1], inp_pipe_op_q[i], reg_ena, fpnew_pkg::FMADD)
`FFL(inp_pipe_op_mod_q[i+1], inp_pipe_op_mod_q[i], reg_ena, '0)
`FFL(inp_pipe_tag_q[i+1], inp_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(inp_pipe_mask_q[i+1], inp_pipe_mask_q[i], reg_ena, '0)
`FFL(inp_pipe_aux_q[i+1], inp_pipe_aux_q[i], reg_ena, AuxType'('0))
end
@ -352,6 +359,7 @@ module fpnew_noncomp #(
fpnew_pkg::classmask_e [0:NUM_OUT_REGS] out_pipe_class_mask_q;
logic [0:NUM_OUT_REGS] out_pipe_is_class_q;
TagType [0:NUM_OUT_REGS] out_pipe_tag_q;
logic [0:NUM_OUT_REGS] out_pipe_mask_q;
AuxType [0:NUM_OUT_REGS] out_pipe_aux_q;
logic [0:NUM_OUT_REGS] out_pipe_valid_q;
// Ready signal is combinatorial for all stages
@ -364,6 +372,7 @@ module fpnew_noncomp #(
assign out_pipe_class_mask_q[0] = class_mask_d;
assign out_pipe_is_class_q[0] = is_class_d;
assign out_pipe_tag_q[0] = inp_pipe_tag_q[NUM_INP_REGS];
assign out_pipe_mask_q[0] = inp_pipe_mask_q[NUM_INP_REGS];
assign out_pipe_aux_q[0] = inp_pipe_aux_q[NUM_INP_REGS];
assign out_pipe_valid_q[0] = inp_pipe_valid_q[NUM_INP_REGS];
// Input stage: Propagate pipeline ready signal to inside pipe
@ -387,6 +396,7 @@ module fpnew_noncomp #(
`FFL(out_pipe_class_mask_q[i+1], out_pipe_class_mask_q[i], reg_ena, fpnew_pkg::QNAN)
`FFL(out_pipe_is_class_q[i+1], out_pipe_is_class_q[i], reg_ena, '0)
`FFL(out_pipe_tag_q[i+1], out_pipe_tag_q[i], reg_ena, TagType'('0))
`FFL(out_pipe_mask_q[i+1], out_pipe_mask_q[i], reg_ena, '0)
`FFL(out_pipe_aux_q[i+1], out_pipe_aux_q[i], reg_ena, AuxType'('0))
end
// Output stage: Ready travels backwards from output side, driven by downstream circuitry
@ -398,6 +408,7 @@ module fpnew_noncomp #(
assign class_mask_o = out_pipe_class_mask_q[NUM_OUT_REGS];
assign is_class_o = out_pipe_is_class_q[NUM_OUT_REGS];
assign tag_o = out_pipe_tag_q[NUM_OUT_REGS];
assign mask_o = out_pipe_mask_q[NUM_OUT_REGS];
assign aux_o = out_pipe_aux_q[NUM_OUT_REGS];
assign out_valid_o = out_pipe_valid_q[NUM_OUT_REGS];
assign busy_o = (| {inp_pipe_valid_q, out_pipe_valid_q});

View file

@ -8,6 +8,8 @@
// 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>
@ -22,9 +24,12 @@ module fpnew_opgroup_block #(
parameter fpnew_pkg::fmt_unit_types_t FmtUnitTypes = '{default: fpnew_pkg::PARALLEL},
parameter fpnew_pkg::pipe_config_t PipeConfig = fpnew_pkg::BEFORE,
parameter type TagType = logic,
parameter int unsigned TrueSIMDClass = 0,
// Do not change
localparam int unsigned NUM_FORMATS = fpnew_pkg::NUM_FP_FORMATS,
localparam int unsigned NUM_OPERANDS = fpnew_pkg::num_operands(OpGroup)
localparam int unsigned NUM_OPERANDS = fpnew_pkg::num_operands(OpGroup),
localparam int unsigned NUM_LANES = fpnew_pkg::max_num_lanes(Width, FpFmtMask, EnableVectors),
localparam type MaskType = logic [NUM_LANES-1:0]
) (
input logic clk_i,
input logic rst_ni,
@ -39,6 +44,7 @@ module fpnew_opgroup_block #(
input fpnew_pkg::int_format_e int_fmt_i,
input logic vectorial_op_i,
input TagType tag_i,
input MaskType simd_mask_i,
// Input Handshake
input logic in_valid_i,
output logic in_ready_o,
@ -90,6 +96,11 @@ module fpnew_opgroup_block #(
assign in_valid = in_valid_i & (dst_fmt_i == fmt); // enable selected format
// Forward masks related to the right SIMD lane
localparam int unsigned INTERNAL_LANES = fpnew_pkg::num_lanes(Width, fpnew_pkg::fp_format_e'(fmt), EnableVectors);
logic [INTERNAL_LANES-1:0] mask_slice;
always_comb for (int b = 0; b < INTERNAL_LANES; b++) mask_slice[b] = simd_mask_i[(NUM_LANES/INTERNAL_LANES)*b];
fpnew_opgroup_fmt_slice #(
.OpGroup ( OpGroup ),
.FpFormat ( fpnew_pkg::fp_format_e'(fmt) ),
@ -97,7 +108,8 @@ module fpnew_opgroup_block #(
.EnableVectors ( EnableVectors ),
.NumPipeRegs ( FmtPipeRegs[fmt] ),
.PipeConfig ( PipeConfig ),
.TagType ( TagType )
.TagType ( TagType ),
.TrueSIMDClass ( TrueSIMDClass )
) i_fmt_slice (
.clk_i,
.rst_ni,
@ -108,6 +120,7 @@ module fpnew_opgroup_block #(
.op_mod_i,
.vectorial_op_i,
.tag_i,
.simd_mask_i ( mask_slice ),
.in_valid_i ( in_valid ),
.in_ready_o ( fmt_in_ready[fmt] ),
.flush_i,
@ -122,9 +135,9 @@ module fpnew_opgroup_block #(
// If the format wants to use merged ops, tie off the dangling ones not used here
end else if (FpFmtMask[fmt] && ANY_MERGED && !IS_FIRST_MERGED) begin : merged_unused
localparam FMT = fpnew_pkg::get_first_enabled_multi(FmtUnitTypes, FpFmtMask);
// Ready is split up into formats
assign fmt_in_ready[fmt] = fmt_in_ready[fpnew_pkg::get_first_enabled_multi(FmtUnitTypes,
FpFmtMask)];
assign fmt_in_ready[fmt] = fmt_in_ready[int'(FMT)];
assign fmt_out_valid[fmt] = 1'b0; // don't emit values
assign fmt_busy[fmt] = 1'b0; // never busy
@ -181,6 +194,7 @@ module fpnew_opgroup_block #(
.int_fmt_i,
.vectorial_op_i,
.tag_i,
.simd_mask_i ( simd_mask_i ),
.in_valid_i ( in_valid ),
.in_ready_o ( fmt_in_ready[FMT] ),
.flush_i,

View file

@ -8,6 +8,8 @@
// 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>
@ -20,8 +22,11 @@ module fpnew_opgroup_fmt_slice #(
parameter int unsigned NumPipeRegs = 0,
parameter fpnew_pkg::pipe_config_t PipeConfig = fpnew_pkg::BEFORE,
parameter type TagType = logic,
parameter int unsigned TrueSIMDClass = 0,
// Do not change
localparam int unsigned NUM_OPERANDS = fpnew_pkg::num_operands(OpGroup)
localparam int unsigned NUM_OPERANDS = fpnew_pkg::num_operands(OpGroup),
localparam int unsigned NUM_LANES = fpnew_pkg::num_lanes(Width, FpFormat, EnableVectors),
localparam type MaskType = logic [NUM_LANES-1:0]
) (
input logic clk_i,
input logic rst_ni,
@ -33,6 +38,7 @@ module fpnew_opgroup_fmt_slice #(
input logic op_mod_i,
input logic vectorial_op_i,
input TagType tag_i,
input MaskType simd_mask_i,
// Input Handshake
input logic in_valid_i,
output logic in_ready_o,
@ -50,7 +56,7 @@ module fpnew_opgroup_fmt_slice #(
);
localparam int unsigned FP_WIDTH = fpnew_pkg::fp_width(FpFormat);
localparam int unsigned NUM_LANES = fpnew_pkg::num_lanes(Width, FpFormat, EnableVectors);
localparam int unsigned SIMD_WIDTH = unsigned'(Width/NUM_LANES);
logic [NUM_LANES-1:0] lane_in_ready, lane_out_valid; // Handshake signals for the lanes
@ -63,6 +69,7 @@ module fpnew_opgroup_fmt_slice #(
logic [NUM_LANES-1:0] lane_ext_bit; // only the first one is actually used
fpnew_pkg::classmask_e [NUM_LANES-1:0] lane_class_mask;
TagType [NUM_LANES-1:0] lane_tags; // only the first one is actually used
logic [NUM_LANES-1:0] lane_masks;
logic [NUM_LANES-1:0] lane_vectorial, lane_busy, lane_is_class; // dito
logic result_is_vector, result_is_class;
@ -113,6 +120,7 @@ module fpnew_opgroup_fmt_slice #(
.op_i,
.op_mod_i,
.tag_i,
.mask_i ( simd_mask_i[lane] ),
.aux_i ( vectorial_op ), // Remember whether operation was vectorial
.in_valid_i ( in_valid ),
.in_ready_o ( lane_in_ready[lane] ),
@ -121,6 +129,7 @@ module fpnew_opgroup_fmt_slice #(
.status_o ( op_status ),
.extension_bit_o ( lane_ext_bit[lane] ),
.tag_o ( lane_tags[lane] ),
.mask_o ( lane_masks[lane] ),
.aux_o ( lane_vectorial[lane] ),
.out_valid_o ( out_valid ),
.out_ready_i ( out_ready ),
@ -174,6 +183,7 @@ module fpnew_opgroup_fmt_slice #(
.op_i,
.op_mod_i,
.tag_i,
.mask_i ( simd_mask_i[lane] ),
.aux_i ( vectorial_op ), // Remember whether operation was vectorial
.in_valid_i ( in_valid ),
.in_ready_o ( lane_in_ready[lane] ),
@ -184,6 +194,7 @@ module fpnew_opgroup_fmt_slice #(
.class_mask_o ( lane_class_mask[lane] ),
.is_class_o ( lane_is_class[lane] ),
.tag_o ( lane_tags[lane] ),
.mask_o ( lane_masks[lane] ),
.aux_o ( lane_vectorial[lane] ),
.out_valid_o ( out_valid ),
.out_ready_i ( out_ready ),
@ -213,7 +224,10 @@ module fpnew_opgroup_fmt_slice #(
assign slice_result[(unsigned'(lane)+1)*FP_WIDTH-1:unsigned'(lane)*FP_WIDTH] = local_result;
// Create Classification results
if ((lane+1)*8 <= Width) begin : vectorial_class // vectorial class blocks are 8bits in size
if (TrueSIMDClass && SIMD_WIDTH >= 10) begin : vectorial_true_class // true vectorial class blocks are 10bits in size
assign slice_vec_class_result[lane*SIMD_WIDTH +: 10] = lane_class_mask[lane];
assign slice_vec_class_result[(lane+1)*SIMD_WIDTH-1 -: SIMD_WIDTH-10] = '0;
end else if ((lane+1)*8 <= Width) begin : vectorial_class // vectorial class blocks are 8bits in size
assign local_sign = (lane_class_mask[lane] == fpnew_pkg::NEGINF ||
lane_class_mask[lane] == fpnew_pkg::NEGNORM ||
lane_class_mask[lane] == fpnew_pkg::NEGSUBNORM ||
@ -246,9 +260,11 @@ module fpnew_opgroup_fmt_slice #(
localparam int unsigned CLASS_VEC_BITS = (NUM_LANES*8 > Width) ? 8 * (Width / 8) : NUM_LANES*8;
// Pad out unused vec_class bits
if (CLASS_VEC_BITS < Width) begin : pad_vectorial_class
assign slice_vec_class_result[Width-1:CLASS_VEC_BITS] = '0;
// Pad out unused vec_class bits if each classify result is on 8 bits
if (!(TrueSIMDClass && SIMD_WIDTH >= 10)) begin
if (CLASS_VEC_BITS < Width) begin : pad_vectorial_class
assign slice_vec_class_result[Width-1:CLASS_VEC_BITS] = '0;
end
end
// localparam logic [Width-1:0] CLASS_VEC_MASK = 2**CLASS_VEC_BITS - 1;
@ -270,7 +286,7 @@ module fpnew_opgroup_fmt_slice #(
automatic fpnew_pkg::status_t temp_status;
temp_status = '0;
for (int i = 0; i < int'(NUM_LANES); i++)
temp_status |= lane_status[i];
temp_status |= lane_status[i] & {5{lane_masks[i]}};
status_o = temp_status;
end
endmodule

View file

@ -8,6 +8,8 @@
// 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>
@ -25,7 +27,9 @@ module fpnew_opgroup_multifmt_slice #(
parameter type TagType = logic,
// Do not change
localparam int unsigned NUM_OPERANDS = fpnew_pkg::num_operands(OpGroup),
localparam int unsigned NUM_FORMATS = fpnew_pkg::NUM_FP_FORMATS
localparam int unsigned NUM_FORMATS = fpnew_pkg::NUM_FP_FORMATS,
localparam int unsigned NUM_SIMD_LANES = fpnew_pkg::max_num_lanes(Width, FpFmtConfig, EnableVectors),
localparam type MaskType = logic [NUM_SIMD_LANES-1:0]
) (
input logic clk_i,
input logic rst_ni,
@ -40,6 +44,7 @@ module fpnew_opgroup_multifmt_slice #(
input fpnew_pkg::int_format_e int_fmt_i,
input logic vectorial_op_i,
input TagType tag_i,
input MaskType simd_mask_i,
// Input Handshake
input logic in_valid_i,
output logic in_ready_o,
@ -65,7 +70,7 @@ module fpnew_opgroup_multifmt_slice #(
fpnew_pkg::maximum($clog2(NUM_FORMATS), $clog2(NUM_INT_FORMATS));
localparam int unsigned AUX_BITS = FMT_BITS + 2; // also add vectorial and integer flags
logic [NUM_LANES-1:0] lane_in_ready, lane_out_valid; // Handshake signals for the lanes
logic [NUM_LANES-1:0] lane_in_ready, lane_out_valid, divsqrt_done, divsqrt_ready; // Handshake signals for the lanes
logic vectorial_op;
logic [FMT_BITS-1:0] dst_fmt; // destination format to pass along with operation
logic [AUX_BITS-1:0] aux_data;
@ -86,6 +91,7 @@ module fpnew_opgroup_multifmt_slice #(
fpnew_pkg::status_t [NUM_LANES-1:0] lane_status;
logic [NUM_LANES-1:0] lane_ext_bit; // only the first one is actually used
TagType [NUM_LANES-1:0] lane_tags; // only the first one is actually used
logic [NUM_LANES-1:0] lane_masks;
logic [NUM_LANES-1:0][AUX_BITS-1:0] lane_aux; // only the first one is actually used
logic [NUM_LANES-1:0] lane_busy; // dito
@ -94,6 +100,8 @@ module fpnew_opgroup_multifmt_slice #(
logic result_fmt_is_int, result_is_cpk;
logic [1:0] result_vec_op; // info for vectorial results (for packing)
logic simd_synch_rdy, simd_synch_done;
// -----------
// Input Side
// -----------
@ -213,6 +221,7 @@ module fpnew_opgroup_multifmt_slice #(
.src_fmt_i,
.dst_fmt_i,
.tag_i,
.mask_i ( simd_mask_i[lane] ),
.aux_i ( aux_data ),
.in_valid_i ( in_valid ),
.in_ready_o ( lane_in_ready[lane] ),
@ -221,6 +230,7 @@ module fpnew_opgroup_multifmt_slice #(
.status_o ( op_status ),
.extension_bit_o ( lane_ext_bit[lane] ),
.tag_o ( lane_tags[lane] ),
.mask_o ( lane_masks[lane] ),
.aux_o ( lane_aux[lane] ),
.out_valid_o ( out_valid ),
.out_ready_i ( out_ready ),
@ -243,14 +253,20 @@ module fpnew_opgroup_multifmt_slice #(
.op_i,
.dst_fmt_i,
.tag_i,
.mask_i ( simd_mask_i[lane] ),
.aux_i ( aux_data ),
.in_valid_i ( in_valid ),
.in_ready_o ( lane_in_ready[lane] ),
.divsqrt_done_o ( divsqrt_done[lane] ),
.simd_synch_done_i( simd_synch_done ),
.divsqrt_ready_o ( divsqrt_ready[lane]),
.simd_synch_rdy_i( simd_synch_rdy ),
.flush_i,
.result_o ( op_result ),
.status_o ( op_status ),
.extension_bit_o ( lane_ext_bit[lane] ),
.tag_o ( lane_tags[lane] ),
.mask_o ( lane_masks[lane] ),
.aux_o ( lane_aux[lane] ),
.out_valid_o ( out_valid ),
.out_ready_i ( out_ready ),
@ -278,6 +294,7 @@ module fpnew_opgroup_multifmt_slice #(
.dst_fmt_i,
.int_fmt_i,
.tag_i,
.mask_i ( simd_mask_i[lane] ),
.aux_i ( aux_data ),
.in_valid_i ( in_valid ),
.in_ready_o ( lane_in_ready[lane] ),
@ -286,6 +303,7 @@ module fpnew_opgroup_multifmt_slice #(
.status_o ( op_status ),
.extension_bit_o ( lane_ext_bit[lane] ),
.tag_o ( lane_tags[lane] ),
.mask_o ( lane_masks[lane] ),
.aux_o ( lane_aux[lane] ),
.out_valid_o ( out_valid ),
.out_ready_i ( out_ready ),
@ -315,9 +333,16 @@ module fpnew_opgroup_multifmt_slice #(
// Set up some constants
localparam int unsigned FP_WIDTH = fpnew_pkg::fp_width(fpnew_pkg::fp_format_e'(fmt));
// only for active formats within the lane
if (ACTIVE_FORMATS[fmt])
if (ACTIVE_FORMATS[fmt]) begin
assign fmt_slice_result[fmt][(LANE+1)*FP_WIDTH-1:LANE*FP_WIDTH] =
local_result[FP_WIDTH-1:0];
end else if ((LANE+1)*FP_WIDTH <= Width) begin
assign fmt_slice_result[fmt][(LANE+1)*FP_WIDTH-1:LANE*FP_WIDTH] =
'{default: lane_ext_bit[LANE]};
end else if (LANE*FP_WIDTH < Width) begin
assign fmt_slice_result[fmt][Width-1:LANE*FP_WIDTH] =
'{default: lane_ext_bit[LANE]};
end
end
// Generate result packing depending on integer format
@ -325,9 +350,14 @@ module fpnew_opgroup_multifmt_slice #(
for (genvar ifmt = 0; ifmt < NUM_INT_FORMATS; ifmt++) begin : pack_int_result
// Set up some constants
localparam int unsigned INT_WIDTH = fpnew_pkg::int_width(fpnew_pkg::int_format_e'(ifmt));
if (ACTIVE_INT_FORMATS[ifmt])
if (ACTIVE_INT_FORMATS[ifmt]) begin
assign ifmt_slice_result[ifmt][(LANE+1)*INT_WIDTH-1:LANE*INT_WIDTH] =
local_result[INT_WIDTH-1:0];
end else if ((LANE+1)*INT_WIDTH <= Width) begin
assign ifmt_slice_result[ifmt][(LANE+1)*INT_WIDTH-1:LANE*INT_WIDTH] = '0;
end else if (LANE*INT_WIDTH < Width) begin
assign ifmt_slice_result[ifmt][Width-1:LANE*INT_WIDTH] = '0;
end
end
end
end
@ -387,6 +417,10 @@ module fpnew_opgroup_multifmt_slice #(
assign {result_vec_op, result_is_cpk} = '0;
end
// Synch lanes if there is more than one
assign simd_synch_rdy = EnableVectors ? &divsqrt_ready : divsqrt_ready[0];
assign simd_synch_done = EnableVectors ? &divsqrt_done : divsqrt_done[0];
// ------------
// Output Side
// ------------
@ -408,7 +442,8 @@ module fpnew_opgroup_multifmt_slice #(
automatic fpnew_pkg::status_t temp_status;
temp_status = '0;
for (int i = 0; i < int'(NUM_LANES); i++)
temp_status |= lane_status[i];
temp_status |= lane_status[i] & {5{lane_masks[i]}};
status_o = temp_status;
end
endmodule

View file

@ -8,6 +8,8 @@
// 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>
@ -89,6 +91,14 @@ package fpnew_pkg;
INT16: return 16;
INT32: return 32;
INT64: return 64;
default: begin
// pragma translate_off
$fatal(1, "Invalid INT format supplied");
// pragma translate_on
// just return any integer to avoid any latches
// hopefully this error is caught by simulation
return INT8;
end
endcase
endfunction
@ -123,6 +133,7 @@ package fpnew_pkg;
RDN = 3'b010,
RUP = 3'b011,
RMM = 3'b100,
ROD = 3'b101, // This mode is not defined in RISC-V FP-SPEC
DYN = 3'b111
} roundmode_e;

View file

@ -8,6 +8,8 @@
// 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>
@ -38,6 +40,7 @@ module fpnew_rounding #(
// 010 | RDN | Round Down (towards -\infty)
// 011 | RUP | Round Up (towards \infty)
// 100 | RMM | Round to Nearest, ties to Max Magnitude
// 101 | ROD | Round towards odd (this mode is not define in RISC-V FP-SPEC)
// others | | *invalid*
always_comb begin : rounding_decision
unique case (rnd_mode_i)
@ -53,6 +56,7 @@ module fpnew_rounding #(
fpnew_pkg::RDN: round_up = (| round_sticky_bits_i) ? sign_i : 1'b0; // to 0 if +, away if -
fpnew_pkg::RUP: round_up = (| round_sticky_bits_i) ? ~sign_i : 1'b0; // to 0 if -, away if +
fpnew_pkg::RMM: round_up = round_sticky_bits_i[1]; // round down if < ulp/2 away, else up
fpnew_pkg::ROD: round_up = ~abs_value_i[0] & (| round_sticky_bits_i);
default: round_up = fpnew_pkg::DONT_CARE; // propagate x
endcase
end

View file

@ -8,6 +8,8 @@
// 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>
@ -16,7 +18,11 @@ module fpnew_top #(
parameter fpnew_pkg::fpu_features_t Features = fpnew_pkg::RV64D_Xsflt,
parameter fpnew_pkg::fpu_implementation_t Implementation = fpnew_pkg::DEFAULT_NOREGS,
parameter type TagType = logic,
parameter int unsigned TrueSIMDClass = 0,
parameter int unsigned EnableSIMDMask = 0,
// Do not change
localparam int unsigned NumLanes = fpnew_pkg::max_num_lanes(Features.Width, Features.FpFmtMask, Features.EnableVectors),
localparam type MaskType = logic [NumLanes-1:0],
localparam int unsigned WIDTH = Features.Width,
localparam int unsigned NUM_OPERANDS = 3
) (
@ -32,6 +38,7 @@ module fpnew_top #(
input fpnew_pkg::int_format_e int_fmt_i,
input logic vectorial_op_i,
input TagType tag_i,
input MaskType simd_mask_i,
// Input Handshake
input logic in_valid_i,
output logic in_ready_o,
@ -85,6 +92,10 @@ module fpnew_top #(
end
end
// Filter out the mask if not used
MaskType simd_mask;
assign simd_mask = simd_mask_i | ~{NumLanes{logic'(EnableSIMDMask)}};
// -------------------------
// Generate Operation Blocks
// -------------------------
@ -111,7 +122,8 @@ module fpnew_top #(
.FmtPipeRegs ( Implementation.PipeRegs[opgrp] ),
.FmtUnitTypes ( Implementation.UnitTypes[opgrp] ),
.PipeConfig ( Implementation.PipeConfig ),
.TagType ( TagType )
.TagType ( TagType ),
.TrueSIMDClass ( TrueSIMDClass )
) i_opgroup_block (
.clk_i,
.rst_ni,
@ -125,6 +137,7 @@ module fpnew_top #(
.int_fmt_i,
.vectorial_op_i,
.tag_i,
.simd_mask_i ( simd_mask ),
.in_valid_i ( in_valid ),
.in_ready_o ( opgrp_in_ready[opgrp] ),
.flush_i,

View file

@ -0,0 +1,25 @@
# 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).
In this sense, we interpret the "Public API" of a hardware module as its port/parameter list.
Versions of the IP in the same major relase are "pin-compatible" with each other. Minor relases are permitted to add new parameters as long as their default bindings ensure backwards compatibility.
## [Unreleased]
### Added
### Changed
### Fixed
## [1.0.4] - 2020-10-05
### Added
- Started formal changelog
### Changed
### Fixed
- Signalling behavior for underflows to 0.0

View file

@ -273,28 +273,14 @@ module norm_div_sqrt_mvp
else if(Exp_in_DI[C_EXP_FP64+1]) //minus //consider format
begin
if(((~Exp_Max_RS_FP32_D[C_EXP_FP32+1])&&FP32_SI) | ((~Exp_Max_RS_FP64_D[C_EXP_FP64+1])&&FP64_SI) | ((~Exp_Max_RS_FP16_D[C_EXP_FP16+1])&&FP16_SI) | ((~Exp_Max_RS_FP16ALT_D[C_EXP_FP16ALT+1])&&FP16ALT_SI) ) //OF EXP<0 after RS
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b1;
Exp_UF_S=1'b0;
Mant_res_norm_D='0;
Exp_res_norm_D='0;
Mant_forround_D='0;
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else //denormal
begin
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b1;
Mant_res_norm_D={Mant_RS_D[C_MANT_FP64:0]};
Exp_res_norm_D='0;
Mant_forround_D={Mant_forsticky_D[C_MANT_FP64+4:0]}; //??
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
Div_Zero_S=1'b0;
Exp_OF_S=1'b0;
Exp_UF_S=1'b1;
Mant_res_norm_D={Mant_RS_D[C_MANT_FP64:0]};
Exp_res_norm_D='0;
Mant_forround_D={Mant_forsticky_D[C_MANT_FP64+4:0]}; //??
Sign_res_D=Sign_in_DI;
NV_OP_S = 1'b0;
end
else if( (Exp_in_DI[C_EXP_FP32]&&FP32_SI) | (Exp_in_DI[C_EXP_FP64]&&FP64_SI) | (Exp_in_DI[C_EXP_FP16]&&FP16_SI) | (Exp_in_DI[C_EXP_FP16ALT]&&FP16ALT_SI) ) //OF

View file

@ -8,7 +8,7 @@
{
upstream:
{
url: https://github.com/pulp-platform/fpnew.git
rev: 79f75e0a0fdab6ebc3840a14077c39f4934321fe
url: https://github.com/openhwgroup/cvfpu
rev: 3116391bf66660f806b45e212b9949c528b4e270
}
}

View file

@ -5,21 +5,21 @@
{
// Name of the project
name: "pulp_fpnew",
name: "openhwgroup_cvfpu",
// Target directory: relative to the location of this script.
target_dir: "pulp-platform/fpnew",
target_dir: "openhwgroup/cvfpu",
// Upstream repository
upstream: {
// URL
url: "https://github.com/pulp-platform/fpnew.git",
url: "https://github.com/openhwgroup/cvfpu",
// revision
rev: "v0.6.2",
rev: "v0.7.0",
}
// Patch dir for local changes
patch_dir: "patches/pulp-platform/fpnew",
patch_dir: "patches/openhwgroup/cvfpu",
// Exclusions from upstream content
exclude_from_upstream: [

View file

@ -1,7 +0,0 @@
.*
!.git*
*.out
*~
/Bender.lock
/Bender.local
build

View file

@ -1,210 +0,0 @@
# 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.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

@ -1,117 +0,0 @@
# 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 | |
| `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 | |
| `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 | |
| `mv_filter` | **ZARUBAF ADD DESCRIPTION** | active | |
### Data Path Elements
| Name | Description | Status | Superseded By |
| :--------------------------- | :----------------------------------------------------------------------------- | :------------- | :------------ |
| `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` | 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_mux` | Ready/valid interface multiplexer | active | |
| `stream_register` | Register with ready/valid interface | active | |
| `stream_fork` | Ready/valid fork | active | |
| `stream_filter` | Ready/valid filter | active | |
| `stream_delay` | Randomize or delay ready/valid interface | active | |
| `popcount` | Combinatorial popcount (hamming weight) | active | |
### Data Structures
| Name | Description | Status | Superseded By |
| :------------------- | :---------------------------------------------- | :------------- | :------------ |
| `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 | |
| `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 |
|-----------------------|-----------------------------------------------------------------|-------------------------------------------------------------------------|
| <code>\`FF</code> | `q_sig`, `d_sig`, `rst_val` | Flip-flop with asynchronous active-low reset (implicit) |
| <code>\`FFAR</code> | `q_sig`, `d_sig`, `rst_val`, `clk_sig`, `arst_sig` | Flip-flop with asynchronous active-high reset |
| <code>\`FFARN</code> | `q_sig`, `d_sig`, `rst_val`, `clk_sig`, `arstn_sig` | Flip-flop with asynchronous active-low reset |
| <code>\`FFSR</code> | `q_sig`, `d_sig`, `rst_val`, `clk_sig`, `rst_sig` | Flip-flop with synchronous active-high reset |
| <code>\`FFSRN</code> | `q_sig`, `d_sig`, `rst_val`, `clk_sig`, `rstn_sig` | Flip-flop with synchronous active-low reset |
| <code>\`FFNR</code> | `q_sig`, `d_sig`, `clk_sig` | Flip-flop without reset |
| | | |
| <code>\`FFL</code> | `q_sig`, `d_sig`, `load_ena`, `rst_val` | Flip-flop with load-enable and asynchronous active-low reset (implicit) |
| <code>\`FFLAR</code> | `q_sig`, `d_sig`, `load_ena`, `rst_val`, `clk_sig`, `arst_sig` | Flip-flop with load-enable and asynchronous active-high reset |
| <code>\`FFLARN</code> | `q_sig`, `d_sig`, `load_ena`, `rst_val`, `clk_sig`, `arstn_sig` | Flip-flop with load-enable and asynchronous active-low reset |
| <code>\`FFLSR</code> | `q_sig`, `d_sig`, `load_ena`, `rst_val`, `clk_sig`, `rst_sig` | Flip-flop with load-enable and synchronous active-high reset |
| <code>\`FFLSRN</code> | `q_sig`, `d_sig`, `load_ena`, `rst_val`, `clk_sig`, `rstn_sig` | Flip-flop with load-enable and synchronous active-low reset |
| <code>\`FFLNR</code> | `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.*

View file

@ -1,224 +0,0 @@
// 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.
// 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 (implicit clock and reset)
// `FFAR: asynchronous active-high reset
// `FFARN: 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 (implicit clock and reset)
// `FFLAR: load-enable and asynchronous active-high reset
// `FFLARN: 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
// Flip-Flop with asynchronous active-low reset (implicit clock and reset)
// __q: Q output of FF
// __d: D input of FF
// __reset_value: value assigned upon reset
// Implicit:
// clk_i: clock input
// rst_ni: reset input (asynchronous, active low)
`define FF(__q, __d, __reset_value) \
always_ff @(posedge clk_i or negedge rst_ni) begin \
if (!rst_ni) 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
`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
// 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
`define FFARN(__q, __d, __reset_value, __clk, __arst_n) \
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 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
`define FFSR(__q, __d, __reset_value, __clk, __reset_clk) \
`ifndef VERILATOR \
/``* 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
`define FFSRN(__q, __d, __reset_value, __clk, __reset_n_clk) \
`ifndef VERILATOR \
/``* 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
// Implicit:
// clk_i: clock input
// rst_ni: reset input (asynchronous, active low)
`define FFL(__q, __d, __load, __reset_value) \
always_ff @(posedge clk_i or negedge rst_ni) begin \
if (!rst_ni) 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
`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
// 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
`define FFLARN(__q, __d, __load, __reset_value, __clk, __arst_n) \
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 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
`define FFLSR(__q, __d, __load, __reset_value, __clk, __reset_clk) \
`ifndef VERILATOR \
/``* 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
`define FFLSRN(__q, __d, __load, __reset_value, __clk, __reset_n_clk) \
`ifndef VERILATOR \
/``* 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
`define FFLARNC(__q, __d, __load, __clear, __reset_value, __clk, __arst_n) \
`ifndef VERILATOR \
/``* 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

@ -1,175 +0,0 @@
// 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

@ -1,134 +0,0 @@
// 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 PTR_WIDTH = LOG_DEPTH+1;
typedef logic [PTR_WIDTH-1:0] pointer_t;
typedef logic [LOG_DEPTH-1:0] index_t;
localparam pointer_t PTR_FULL = (1 << LOG_DEPTH);
localparam pointer_t PTR_EMPTY = '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) != PTR_FULL);
assign dst_valid_o = ((dst_rptr_q ^ dst_wptr) != PTR_EMPTY);
// Transport the read and write pointers across the clock domain boundary.
cdc_2phase #(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 #(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

@ -1,158 +0,0 @@
// 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 gray counters.
///
/// 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.
///
/// # Constraints
///
/// The following constraints need to be set:
/// - max_delay -from src_wptr_gray_q -to dst_wptr_gray_q
/// - max_delay -from dst_rptr_gray_q -to src_rptr_gray_q
/// - max_delay -from fifo_data_q -to fifo_rdata
module cdc_fifo_gray #(
/// 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 PTR_WIDTH = LOG_DEPTH+1;
typedef logic [PTR_WIDTH-1:0] pointer_t;
typedef logic [LOG_DEPTH-1:0] index_t;
localparam pointer_t PTR_FULL = (1 << LOG_DEPTH);
localparam pointer_t PTR_EMPTY = '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
// Create the write and read pointers in the source and destination domain.
// These are binary counters combined with a Gray encoder. Both the binary and
// the Gray coded output are registered; the binary one for use in the local
// domain, the Gray one for synchronization into the other domain.
pointer_t src_wptr_bin_q, src_wptr_gray_q, dst_rptr_bin_q, dst_rptr_gray_q;
pointer_t src_wptr_bin_d, src_wptr_gray_d, dst_rptr_bin_d, dst_rptr_gray_d;
assign src_wptr_bin_d = src_wptr_bin_q + 1;
assign dst_rptr_bin_d = dst_rptr_bin_q + 1;
binary_to_gray #(PTR_WIDTH) i_src_b2g (src_wptr_bin_d, src_wptr_gray_d);
binary_to_gray #(PTR_WIDTH) i_dst_b2g (dst_rptr_bin_d, dst_rptr_gray_d);
always_ff @(posedge src_clk_i, negedge src_rst_ni) begin
if (!src_rst_ni) begin
src_wptr_bin_q <= '0;
src_wptr_gray_q <= '0;
end else if (src_valid_i && src_ready_o) begin
src_wptr_bin_q <= src_wptr_bin_d;
src_wptr_gray_q <= src_wptr_gray_d;
end
end
always_ff @(posedge dst_clk_i, negedge dst_rst_ni) begin
if (!dst_rst_ni) begin
dst_rptr_bin_q <= '0;
dst_rptr_gray_q <= '0;
end else if (dst_valid_o && dst_ready_i) begin
dst_rptr_bin_q <= dst_rptr_bin_d;
dst_rptr_gray_q <= dst_rptr_gray_d;
end
end
// Move the Gray-coded pointers over into the other clock domain and
// synchronize them to reduce the probability of metastability.
pointer_t src_rptr_gray_q, src_rptr_gray_q2;
pointer_t dst_wptr_gray_q, dst_wptr_gray_q2;
always_ff @(posedge src_clk_i, negedge src_rst_ni) begin
if (!src_rst_ni) begin
src_rptr_gray_q <= '0;
src_rptr_gray_q2 <= '0;
end else begin
src_rptr_gray_q <= dst_rptr_gray_q;
src_rptr_gray_q2 <= src_rptr_gray_q;
end
end
always_ff @(posedge dst_clk_i, negedge dst_rst_ni) begin
if (!dst_rst_ni) begin
dst_wptr_gray_q <= '0;
dst_wptr_gray_q2 <= '0;
end else begin
dst_wptr_gray_q <= src_wptr_gray_q;
dst_wptr_gray_q2 <= dst_wptr_gray_q;
end
end
// Reverse the Gray coding of the synchronized pointers.
pointer_t src_rptr_bin, dst_wptr_bin;
gray_to_binary #(PTR_WIDTH) i_src_g2b (src_rptr_gray_q2, src_rptr_bin);
gray_to_binary #(PTR_WIDTH) i_dst_g2b (dst_wptr_gray_q2, dst_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 src_ready_o = ((src_wptr_bin_q ^ src_rptr_bin) != PTR_FULL);
assign dst_valid_o = ((dst_rptr_bin_q ^ dst_wptr_bin) != PTR_EMPTY);
// Drive the FIFO write and read ports.
assign fifo_widx = src_wptr_bin_q;
assign fifo_wdata = src_data_i;
assign fifo_write = src_valid_i && src_ready_o;
assign fifo_ridx = dst_rptr_bin_q;
assign dst_data_o = fifo_rdata;
endmodule

View file

@ -1,49 +0,0 @@
// 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 automatic cf_math_pkg;
// Ceiled Division of Two Natural Numbers
//
// Returns the quotient of two natural numbers, rounded towards plus infinity.
function 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
endpackage

View file

@ -1,42 +0,0 @@
// 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

@ -1,55 +0,0 @@
// 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
)(
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
);
logic [WIDTH:0] counter_q, counter_d;
// counter overflowed if the MSB is set
assign overflow_o = counter_q[WIDTH];
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 - 1;
end else begin
counter_d = counter_q + 1;
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

@ -1,191 +0,0 @@
// 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

@ -1,211 +0,0 @@
// 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

@ -1,57 +0,0 @@
// 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

@ -1,79 +0,0 @@
// 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

@ -1,83 +0,0 @@
// 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

@ -1,64 +0,0 @@
// 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

@ -1,274 +0,0 @@
// 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

@ -1,264 +0,0 @@
// 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

@ -1,89 +0,0 @@
// 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

@ -1,36 +0,0 @@
// 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

@ -1,55 +0,0 @@
// 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

@ -1,61 +0,0 @@
// 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

@ -1,32 +0,0 @@
// 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

@ -1,50 +0,0 @@
// 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

@ -1,31 +0,0 @@
// 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

@ -1,40 +0,0 @@
// 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

@ -1,94 +0,0 @@
// 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 #(
parameter int unsigned Seed = 'hffff, // seed for 16bit lfsr
parameter int unsigned MaxExp = 16 // 2**MaxExp-1 determines the maximum range from which random wait counts are drawn
) (
input logic clk_i,
input logic rst_ni,
//
input logic set_i, // sets the backoff counter (pulse) -> use when trial did not succeed
input logic clr_i, // clears the backoff counter (pulse) -> use when trial succeeded
output logic is_zero_o // indicates whether the backoff counter is equal to zero and a new trial can be launched
);
// leave this constant
localparam 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

@ -1,58 +0,0 @@
// 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

@ -1,153 +0,0 @@
// 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 FIFO_DEPTH = (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
logic [ADDR_DEPTH:0] status_cnt_n, status_cnt_q; // this integer will be truncated by the synthesis tool
// actual memory
dtype [FIFO_DEPTH - 1:0] mem_n, mem_q;
assign usage_o = status_cnt_q[ADDR_DEPTH-1:0];
if (DEPTH == 0) begin
assign empty_o = ~push_i;
assign full_o = ~pop_i;
end else begin
assign full_o = (status_cnt_q == FIFO_DEPTH[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 == FIFO_DEPTH[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 == FIFO_DEPTH[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

@ -1,33 +0,0 @@
// 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
/// 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

@ -1,268 +0,0 @@
// 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. 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.
//
// 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 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 N_IDS = 2**ID_WIDTH;
localparam int HT_CAPACITY = (N_IDS <= CAPACITY) ? N_IDS : CAPACITY;
// Type for indexing the head-tail table.
typedef logic [$clog2(HT_CAPACITY)-1:0] ht_idx_t;
// Type for indexing the lined data table.
typedef logic [$clog2(CAPACITY)-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 [HT_CAPACITY-1:0] head_tail_d, head_tail_q;
linked_data_t [CAPACITY-1:0] linked_data_d, linked_data_q;
logic full,
match_id_valid,
no_id_match;
logic [HT_CAPACITY-1:0] head_tail_free,
idx_matches_id;
logic [CAPACITY-1:0] exists_match,
linked_data_free;
id_t match_id;
ht_idx_t head_tail_free_idx,
match_idx;
ld_idx_t linked_data_free_idx;
// Find the index in the head-tail table that matches a given ID.
for (genvar i = 0; i < HT_CAPACITY; i++) begin: gen_idx_match
assign idx_matches_id[i] = match_id_valid && (head_tail_q[i].id == match_id) &&
!head_tail_q[i].free;
end
assign no_id_match = !(|idx_matches_id);
onehot_to_bin #(
.ONEHOT_WIDTH (HT_CAPACITY)
) i_id_ohb (
.onehot (idx_matches_id),
.bin (match_idx)
);
// Find the first free index in the head-tail table.
for (genvar i = 0; i < HT_CAPACITY; i++) begin: gen_head_tail_free
assign head_tail_free[i] = head_tail_q[i].free;
end
lzc #(
.WIDTH (HT_CAPACITY),
.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);
assign inp_gnt_o = ~full;
always_comb begin
match_id = 'x;
match_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'('x);
oup_data_valid_o = 1'b0;
if (inp_req_i && !full) begin
match_id = inp_id_i;
match_id_valid = 1'b1;
// If the ID does not yet exist in the queue, add a new ID entry.
if (no_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_idx].tail].next = linked_data_free_idx;
head_tail_d[match_idx].tail = linked_data_free_idx;
end
linked_data_d[linked_data_free_idx] = '{
data: inp_data_i,
next: 'x,
free: 1'b0
};
end else if (oup_req_i) begin
match_id = oup_id_i;
match_id_valid = 1'b1;
if (!no_id_match) begin
oup_data_o = data_t'(linked_data_q[head_tail_q[match_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_idx].head] = 'x;
linked_data_d[head_tail_q[match_idx].head][0] = 1'b1;
if (head_tail_q[match_idx].head == head_tail_q[match_idx].tail) begin
head_tail_d[match_idx] = '{free: 1'b1, default: 'x};
end else begin
head_tail_d[match_idx].head = linked_data_q[head_tail_q[match_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
// 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 = 'x;
if (exists_req_i) begin
exists_gnt_o = 1'b1;
exists_o = (|exists_match);
end
end
// Registers
for (genvar i = 0; i < CAPACITY; i++) begin: gen_ffs
always_ff @(posedge clk_i, negedge rst_ni) begin
if (!rst_ni) begin
head_tail_q[i] <= '{free: 1'b1, default: 'x};
// Set free bit of linked data entries, all other bits are don't care.
linked_data_q[i] <= 'x;
linked_data_q[i][0] <= 1'b1;
end else begin
head_tail_q[i] <= head_tail_d[i];
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("The ID must at least be one bit wide!");
assert (CAPACITY >= 1)
else $fatal("The queue must have capacity of at least one entry!");
end
`endif
// pragma translate_on
endmodule

View file

@ -1,310 +0,0 @@
// 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

@ -1,67 +0,0 @@
// 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 LOG_WIDTH = $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[LOG_WIDTH-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

@ -1,68 +0,0 @@
// 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 LFSR
// --------------
//
// Description: 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 LOG_WIDTH = $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[LOG_WIDTH-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

@ -1,93 +0,0 @@
// 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,
parameter bit MODE = 1'b0 // 0 -> trailing zero, 1 -> leading zero
) (
input logic [WIDTH-1:0] in_i,
output logic [$clog2(WIDTH)-1:0] cnt_o,
output logic empty_o // asserted if all bits in in_i are zero
);
localparam int unsigned NUM_LEVELS = $clog2(WIDTH);
// pragma translate_off
initial begin
assert(WIDTH > 0) else $fatal("input must be at least one bit wide");
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;
// 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] = NUM_LEVELS'(unsigned'(j));
end
for (genvar level = 0; unsigned'(level) < NUM_LEVELS; level++) begin : g_levels
if (unsigned'(level) == NUM_LEVELS-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
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
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
assign sel_nodes[2**level-1+k] = 1'b0;
assign index_nodes[2**level-1+k] = '0;
end
end
end else begin
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 = NUM_LEVELS > unsigned'(0) ? index_nodes[0] : $clog2(WIDTH)'(0);
assign empty_o = NUM_LEVELS > unsigned'(0) ? ~sel_nodes[0] : ~(|in_i);
endmodule : lzc

View file

@ -1,55 +0,0 @@
// 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

@ -1,39 +0,0 @@
// 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 = $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
initial begin
assert($onehot0(onehot)) else $fatal(1, "[onehot_to_bin] More than two bit set in the one-hot signal");
end
`endif
// pragma translate_on
endmodule

View file

@ -1,120 +0,0 @@
// 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 LOG_ENTRIES = $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 < LOG_ENTRIES; lvl++) begin
idx_base = $unsigned((2**lvl)-1);
// lvl0 <=> MSB, lvl1 <=> MSB-1, ...
shift = LOG_ENTRIES - lvl;
// to circumvent the 32 bit integer arithmetic assignment
new_index = ~((i >> (shift-1)) & 32'b1);
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 < LOG_ENTRIES; lvl++) begin
idx_base = $unsigned((2**lvl)-1);
// lvl0 <=> MSB, lvl1 <=> MSB-1, ...
shift = LOG_ENTRIES - lvl;
// en &= plru_tree_q[idx_base + (i>>shift)] == ((i >> (shift-1)) & 1'b1);
new_index = (i >> (shift-1)) & 32'b1;
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**LOG_ENTRIES) else $error("Entries must be a power of two");
end
`endif
// pragma translate_on
endmodule

View file

@ -1,57 +0,0 @@
// 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 POPCOUNT_WIDTH = $clog2(INPUT_WIDTH)+1
) (
input logic [INPUT_WIDTH-1:0] data_i,
output logic [POPCOUNT_WIDTH-1:0] popcount_o
);
localparam int unsigned PADDED_WIDTH = 1 << $clog2(INPUT_WIDTH);
logic [PADDED_WIDTH-1:0] padded_input;
logic [POPCOUNT_WIDTH-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 == 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(PADDED_WIDTH / 2))
left_child(
.data_i(padded_input[PADDED_WIDTH-1:PADDED_WIDTH/2]),
.popcount_o(left_child_result));
popcount #(.INPUT_WIDTH(PADDED_WIDTH / 2))
right_child(
.data_i(padded_input[PADDED_WIDTH/2-1:0]),
.popcount_o(right_child_result));
end
//Output assignment
assign popcount_o = left_child_result + right_child_result;
endmodule : popcount

View file

@ -1,244 +0,0 @@
// 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: 02.04.2019
// Description: logarithmic arbitration tree with round robin arbitration scheme.
//
// The rr_arb_tree employs fair round robin arbitration - i.e. the priorities
// rotate each cycle.
//
// 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.
//
// 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.
//
// 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.
//
module rr_arb_tree #(
parameter int unsigned NumIn = 64,
parameter int unsigned DataWidth = 32,
parameter type DataType = logic [DataWidth-1:0],
parameter bit ExtPrio = 1'b0, // set to 1'b1 to enable
parameter bit AxiVldRdy = 1'b0, // treat req/gnt as vld/rdy
parameter bit LockIn = 1'b0 // set to 1'b1 to enable
) (
input logic clk_i,
input logic rst_ni,
input logic flush_i, // clears the arbiter state
input logic [$clog2(NumIn)-1:0] rr_i, // external RR prio (needs to be enabled above)
// input requests and data
input logic [NumIn-1:0] req_i,
/* verilator lint_off UNOPTFLAT */
output logic [NumIn-1:0] gnt_o,
/* verilator lint_on UNOPTFLAT */
input DataType [NumIn-1:0] data_i,
// arbitrated output
input logic gnt_i,
output logic req_o,
output DataType data_o,
output logic [$clog2(NumIn)-1:0] idx_o
);
// just pass through in this corner case
if (NumIn == unsigned'(1)) begin
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
localparam int unsigned NumLevels = $clog2(NumIn);
/* verilator lint_off UNOPTFLAT */
logic [2**NumLevels-2:0][NumLevels-1: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 */
logic [NumLevels-1:0] 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
logic [NumLevels-1:0] 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) disable iff (!rst_ni) LockIn |-> req_o && !gnt_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: assert property(
@(posedge clk_i) disable iff (!rst_ni) 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
assign rr_d = (gnt_i && req_o) ? ((rr_q == NumLevels'(NumIn-1)) ? '0 : rr_q + 1'b1) : rr_q;
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
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] = NumLevels'(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
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
assign req_nodes[idx0] = 1'b0;
assign index_nodes[idx0] = DataType'('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) ? NumLevels'({1'b1, index_nodes[idx1+1][NumLevels-unsigned'(level)-2:0]}) :
NumLevels'({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
initial begin : p_assert
assert(NumIn)
else $fatal("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) disable iff (!rst_ni) $onehot0(gnt_o))
else $fatal (1, "Grant signal must be hot1 or zero.");
gnt0 : assert property(
@(posedge clk_i) disable iff (!rst_ni) |gnt_o |-> gnt_i)
else $fatal (1, "Grant out implies grant in.");
gnt1 : assert property(
@(posedge clk_i) disable iff (!rst_ni) req_o |-> gnt_i |-> |gnt_o)
else $fatal (1, "Req out and grant in implies grant out.");
gnt_idx : assert property(
@(posedge clk_i) disable iff (!rst_ni) req_o |-> gnt_i |-> gnt_o[idx_o])
else $fatal (1, "Idx_o / gnt_o do not match.");
req0 : assert property(
@(posedge clk_i) disable iff (!rst_ni) |req_i |-> req_o)
else $fatal (1, "Req in implies req out.");
req1 : assert property(
@(posedge clk_i) disable iff (!rst_ni) |req_o |-> req_i)
else $fatal (1, "Req out implies req in.");
`endif
// pragma translate_on
end
endmodule : rr_arb_tree

View file

@ -1,30 +0,0 @@
// 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

@ -1,54 +0,0 @@
// 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 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
initial begin : p_assertions
if (NumRegs < 1) $fatal(1, "At least one register is required.");
end
endmodule

View file

@ -1,50 +0,0 @@
// 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

@ -1,53 +0,0 @@
// 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
assign d_o = d_i;
// register of depth 1 is a simple register
end else if (Depth == 1) begin
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
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

@ -1,89 +0,0 @@
// 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 register with handshakes that completely cuts any combinational paths
/// between the input and output.
module spill_register #(
parameter type T = logic
)(
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
);
// The A register.
T a_data_q;
logic a_full_q;
logic a_fill, a_drain;
logic a_en, a_en_data;
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.
assign a_fill = valid_i && ready_o;
assign a_drain = a_full_q && !b_full_q;
// 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.
assign b_fill = a_drain && !ready_i;
assign b_drain = b_full_q && ready_i;
// We can accept input as long as register B is not full.
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;
endmodule

View file

@ -1,46 +0,0 @@
// 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

@ -1,49 +0,0 @@
// 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

@ -1,80 +0,0 @@
// 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
$fatal(1, "Invalid value for parameter 'ARBITER'!");
end
endmodule

View file

@ -1,132 +0,0 @@
// 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 : pass_through
assign ready_o = ready_i;
assign valid_o = valid_i;
assign payload_o = payload_i;
end else begin
localparam COUNTER_BITS = 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 [COUNTER_BITS-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 : 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
assign counter_load = FixedDelay;
end
counter #(
.WIDTH ( COUNTER_BITS )
) 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

@ -1,37 +0,0 @@
// 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 demultiplexer: 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 #(
parameter integer N_OUP = 1,
/// Dependent parameters, DO NOT OVERRIDE!
localparam integer LOG_N_OUP = $clog2(N_OUP)
) (
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

@ -1,26 +0,0 @@
// 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

@ -1,133 +0,0 @@
// 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("Number of outputs must be at least 1!");
end
`endif
// pragma translate_on
endmodule

View file

@ -1,46 +0,0 @@
// 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!
localparam 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 ("The number of inputs must be at least 1!");
end
`endif
// pragma translate_on
endmodule

View file

@ -1,57 +0,0 @@
// 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 ($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

@ -1,34 +0,0 @@
// 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
) (
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 <= 'h0;
end else begin
reg_q <= {reg_q[STAGES-2:0], serial_i};
end
end
assign serial_o = reg_q[STAGES-1];
endmodule

View file

@ -1,56 +0,0 @@
// 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

@ -1,21 +0,0 @@
// 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 */

View file

@ -1,176 +0,0 @@
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

@ -1,14 +0,0 @@
// 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.
{
upstream:
{
url: https://github.com/pulp-platform/common_cells.git
rev: 790f2385c01c83022474eede55809666209216e3
}
}

View file

@ -1,41 +0,0 @@
// -*- coding: utf-8 -*-
// Copyright (C) 2022 Thales DIS France SAS
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0.
// Original Author: Zbigniew Chamski (zbigniew.chamski@thalesgroup.com)
{
// Name of the project
name: "pulp_common_cells_fpu",
// Target directory: relative to the location of this script.
target_dir: "pulp-platform/fpnew/src/common_cells",
// Upstream repository
upstream: {
// URL
url: "https://github.com/pulp-platform/common_cells.git",
// revision
rev: "v1.13.1",
}
//Patch dir for local changes
patch_dir: "patches/pulp-platform/common_cells_fpu",
// Exclusions from upstream content
exclude_from_upstream: [
".git",
".github",
".gitlab-ci.yml",
".travis.yml",
"Bender.yml",
"ci",
"common_cells.core",
"formal",
"ips_list.yml",
"lint",
"Makefile",
"src_files.yml",
"test",
]
}

View file

@ -9,6 +9,6 @@
upstream:
{
url: https://github.com/pulp-platform/fpu_div_sqrt_mvp.git
rev: 83a601f97934ed5e06d737b9c80d98b08867c5fa
rev: 86e1f558b3c95e91577c41b2fc452c86b04e85ac
}
}

View file

@ -8,14 +8,14 @@
name: "pulp_fpu_div_sqrt_mvp",
// Target directory: relative to the location of this script.
target_dir: "pulp-platform/fpnew/src/fpu_div_sqrt_mvp",
target_dir: "openhwgroup/cvfpu/src/fpu_div_sqrt_mvp",
// Upstream repository
upstream: {
// URL
url: "https://github.com/pulp-platform/fpu_div_sqrt_mvp.git",
// revision
rev: "v1.0.3",
rev: "v1.0.4",
}
//Patch dir for local changes