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_int_div
Arbitrary integer clock divider with config interface and 50% output clock duty cycle
active
clk_int_div_static
A convenience wrapper around clk_int_div with static division factor.
active
clk_div
Clock divider with integer divisor
deprecated
clk_int_div
clock_divider
Clock divider with configuration registers
deprecated
clk_int_div
clock_divider_counter
Clock divider using a counter
deprecated
clk_int_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_4phase
Clock domain crossing using 4-phase handshake, with ready/valid interface
active
cdc_2phase
Clock domain crossing using two-phase handshake, with ready/valid interface
active
cdc_2phase_clearable
Identical to cdc_2phase but supports one-sided async/sync resetting of either src or dst
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
cdc_fifo_gray_clearable
Identical to cdc_fifo_gray but supports one-sided async/sync resetting of either src or dst
active
cdc_reset_ctrlr
Lock-step reset sequencer accross clock domains (internally used by clearable CDCs)
active
clk_mux_glitch_free
A glitch-free clock multiplexer with parametrizeable number of inputs.
active
edge_detect
Rising/falling edge detector
active
edge_propagator
Propagates a single-cycle pulse across an asynchronous clock domain crossing
active
edge_propagator_ack
edge_propagator with sender-synchronous acknowledge pin (flags received pulse)
active
edge_propagator_rx
Receive slice of edge_propagator, requires only the receiver clock
active
edge_propagator_tx
Transmit slice of edge_propagator, requires only the sender clock
active
isochronous_spill_register
Isochronous clock domain crossing and full handshake (like spill_register)
active
isochronous_4phase_handshake
Isochronous four-phase handshake.
active
pulp_sync
Serial line synchronizer
deprecated
sync
pulp_sync_wedge
Serial line synchronizer with edge detector
deprecated
sync_wedge
serial_deglitch
Serial line deglitcher
active
sync
Serial line synchronizer
active
sync_wedge
Serial line synchronizer with edge detector
active
Counters and Shift Registers
Name
Description
Status
Superseded By
counter
Generic up/down counter with overflow detection
active
delta_counter
Up/down counter with variable delta and overflow detection
active
generic_LFSR_8bit
8-bit linear feedback shift register (LFSR)
deprecated
lfsr_8bit
lfsr_8bit
8-bit linear feedback shift register (LFSR)
active
lfsr_16bit
16-bit linear feedback shift register (LFSR)
active
lfsr
4...64-bit parametric Galois LFSR with optional whitening feature
active
max_counter
Up/down counter with variable delta that tracks its maximum value
active
mv_filter
ZARUBAF ADD DESCRIPTION
active
Data Path Elements
Name
Description
Status
Superseded By
addr_decode
Address map decoder
active
addr_decode_dync
Address map decoder extended to support dynamic online configuration
active
addr_decode_napot
Address map decoder using naturally-aligned power of two (NAPOT) regions
active
multiaddr_decode
Address map decoder using NAPOT regions and allowing for multiple address inputs
Round-robin arbiter for req/gnt and vld/rdy interfaces with optional priority
active
rrarbiter
Round-robin arbiter for req/ack interface with look-ahead
deprecated
rr_arb_tree
prioarbiter
Priority arbiter arbiter for req/ack interface with look-ahead
deprecated
rr_arb_tree
fall_through_register
Fall-through register with ready/valid interface
active
spill_register_flushable
Register with ready/valid interface to cut all combinational interface paths and additional flush signal.
active
spill_register
Register with ready/valid interface to cut all combinational interface paths
active
stream_arbiter
Round-robin arbiter for ready/valid stream interface
active
stream_arbiter_flushable
Round-robin arbiter for ready/valid stream interface and flush functionality
active
stream_demux
Ready/valid interface demultiplexer
active
lossy_valid_to_stream
Convert Valid-only to ready/valid by updating in-flight transaction
active
stream_join
Ready/valid handshake join multiple to one common
active
stream_join_dynamic
Ready/valid handshake join multiple to one common, dynamically configurable subset selection
active
stream_mux
Ready/valid interface multiplexer
active
stream_register
Register with ready/valid interface
active
stream_fork
Ready/valid fork
active
stream_fork_dynamic
Ready/valid fork, with selection mask for partial forking
active
stream_filter
Ready/valid filter
active
stream_delay
Randomize or delay ready/valid interface
active
stream_to_mem
Use memories without flow control for output data in streams.
active
stream_xbar
Fully connected crossbar with ready/valid interface.
active
stream_omega_net
One-way stream omega-net with ready/valid interface. Isomorphic to a butterfly.
active
stream_throttle
Restrict the number of outstanding transfers in a stream.
active
sub_per_hash
Substitution-permutation hash function
active
popcount
Combinatorial popcount (hamming weight)
active
mem_to_banks_detailed
Split memory access over multiple parallel banks with detailed response signals
active
mem_to_banks
Split memory access over multiple parallel banks
active
Data Structures
Name
Description
Status
Superseded By
cb_filter
Counting-Bloom-Filter with combinational lookup
active
fifo
FIFO register with upper threshold
deprecated
fifo_v3
fifo_v2
FIFO register with upper and lower threshold
deprecated
fifo_v3
fifo_v3
FIFO register with generic fill counts
active
passthrough_stream_fifo
FIFO register with ready/valid interface and same-cycle push/pop when full
active
stream_fifo
FIFO register with ready/valid interface
active
stream_fifo_optimal_wrap
Wrapper that optimally selects either a spill register or a FIFO
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
read
Dummy module that prevents a signal from being removed during synthesis
active
Header Contents
This repository currently contains the following header files.
RTL Register Macros
The header file registers.svh contains macros that expand to descriptions of registers.
To avoid misuse of always_ff blocks, only the following macros shall be used to describe sequential behavior.
The use of linter rules that flag explicit uses of always_ff in source code is encouraged.
Macro
Arguments
Description
`FF
q_sig, d_sig, rst_val, (clk_sig, arstn_sig)
Flip-flop with asynchronous active-low reset
`FFAR
q_sig, d_sig, rst_val, clk_sig, arst_sig
Flip-flop with asynchronous active-high reset
`FFARN
q_sig, d_sig, rst_val, clk_sig, arstn_sig
deprecated Flip-flop with asynchronous active-low reset
Flip-flop with load-enable and synchronous active-low reset
`FFLNR
q_sig, d_sig, load_ena, clk_sig
Flip-flop with load-enable without reset
The name of the clock and reset signals for implicit variants is clk_i and rst_ni, respectively.
Argument suffix _sig indicates signal names for present and next state as well as clocks and resets.
Argument rst_val specifies the value literal to be assigned upon reset.
Argument load_ena specifies the boolean expression that forms the load enable of the register.
SystemVerilog Assertion Macros
The header file assertions.svh contains macros that expand to assertion blocks.
These macros should recduce the effort in writing many assertions and make it
easier to use them. They are identical with the macros used by lowrisc
and just re-implemented here for the sake of easier use in PULP projects (the same include guard is used so they should not clash).
Simple Assertion and Cover Macros
Macro
Arguments
Description
`ASSERT_I
__name, __prop
Immediate assertion
`ASSERT_INIT
__name, __prop
Assertion in initial block. Can be used for things like parameter checking
`ASSERT_FINAL
__name, __prop
Assertion in final block
`ASSERT
__name, __prop, (__clk, __rst)
Assert a concurrent property directly
`ASSERT_NEVER
__name, __prop, (__clk, __rst)
Assert a concurrent property NEVER happens
`ASSERT_KNOWN
__name, __sig, (__clk, __rst)
Concurrent clocked assertion with custom error message
`COVER
__name, __prop, (__clk, __rst)
Cover a concurrent property
The name of the clock and reset signals for implicit variants is clk_i and rst_ni, respectively.
Complex Assertion Macros
Macro
Arguments
Description
`ASSERT_PULSE
__name, __sig, (__clk, __rst)
Assert that signal is an active-high pulse with pulse length of 1 clock cycle
`ASSERT_IF
__name, __prop, __enable, (__clk, __rst)
Assert that a property is true only when an enable signal is set
`ASSERT_KNOWN_IF
__name, __sig, __enable, (__clk, __rst)
Assert that signal has a known value (each bit is either '0' or '1') after reset if enable is set
The name of the clock and reset signals for implicit variants is clk_i and rst_ni, respectively.
Assumption Macros
Macro
Arguments
Description
`ASSUME
__name, __prop, (__clk, __rst)
Assume a concurrent property
`ASSUME_I
__name, __prop
Assume an immediate property
The name of the clock and reset signals for implicit variants is clk_i and rst_ni, respectively.
Formal Verification Macros
Macro
Arguments
Description
`ASSUME_FPV
__name, __prop, (__clk, __rst)
Assume a concurrent property during formal verification only
`ASSUME_I_FPV
__name, __prop
Assume a concurrent property during formal verification only
`COVER_FPV
__name, __prop, (__clk, __rst)
Cover a concurrent property during formal verification
The name of the clock and reset signals for implicit variants is clk_i and rst_ni, respectively.
it seems that most of the modules in this repository exclude assertions when simulating with Verilator. Typically, the assertions are surrounded by an ifndef - endif block that excludes them in Verilator, such as for instance in the fifo_v3:
else$fatal (1, "Trying to pop data although the FIFO is empty.");
`endif
Verilator has had support for assert properties since at least version 3.922 released in 2018 and support for the implication operator has been added in version 4.026 released in 2020. AFAIK the initial block is a bit more of a recent addition, but has also been supported for a while now.
Is there a particular reason why assertions are excluded in Verilator (e.g., this repo must support some version of Verilator that cannot handle assert properties)? Could this restriction be lifted given the time that Verilator already has had support for this?
The edge_detect, edge_propagator, edge_propagator_rx, and sync modules depend on some deprecated and pulp_* modules defined outside of the repo. Maybe we should just drop these cells? Or rewrite them to not use manual clock gating.
The PTW currently has an exclusive readport into the dcache. This is overprovisioning, as PTWs should not occur frequently. Sharing the read port with the load unit should lead to lower HW complexity and better timing in the dcache.
The usage_o port of fifo_v3 has currently a width of $clog(DEPTH).
This causes the pointer to wrap around to all zeros, if the FIFO has a power of 2 DEPTH and is full. This is an issue for the following exapmle:
localparam intunsigned Depth =32'd16;
localparam logic [3:0] Threshold =4'hF;
logic [3:0] usage;
if (usage > threshold) begin/* do something */end
This if statement would not trigger in this case.
This could be resolved by assigning the whole status_cnt_q to the usage_o port instead of the truncated one as is currently the case.
The workaround I am using currently is prepending the full_o signal to the ussage_o, however this causes jumps in this new usage pointer value when the FIFO is not configured to a power of 2 DEPTH.
I get a synthesis warning that the index of head_tail_q is out of bounds.
Relevant code Line 247:
// 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
Should it not be?:
for (genvar i = 0; i < HT_CAPACITY; i++) begin: gen_ffs
As HT_CAPACITY can be lower than CAPACITY in certain configurations:
Right now the synchronizers are behavioral descriptions which should be changed to instantiation of synch primitives as more sophisticated cell libraries usually have dedicated synchronization cells which give maximum resolution time for mitigating meta stability effects.
I'm facing a problem using the stream_register required for using Pulp AXI. This module is included in the axi_atop_filter. Unfortunately I get the following error message during compilation with Synopsys Synplify :
When elaborating the following problem occurs in DC. We should fix this pls.
Warning: ../../src/fpnew/src/common_cells/src/lzc.sv:52: signed to unsigned conversion occurs. (VER-318)
Warning: ../../src/fpnew/src/common_cells/src/lzc.sv:58: signed to unsigned conversion occurs. (VER-318)
Warning: ../../src/fpnew/src/common_cells/src/lzc.sv:64: signed to unsigned conversion occurs. (VER-318)
Warning: ../../src/fpnew/src/common_cells/src/lzc.sv:69: signed to unsigned conversion occurs. (VER-318)
Warning: ../../src/fpnew/src/common_cells/src/lzc.sv:58: signed to unsigned conversion occurs. (VER-318)
The use of $clog2 on a (generally non-static) function argument does not compile unless using the last year's [synthesis tool that shall not be named] or newer.
This is bad since functions from cf_math_pkg were shoehorned into other common cells and subsequently massively break tool compatibility of IPs using common cells such as fpnew.
I'm not sure what the correct solution to the problem is because the use of clog2 is not illegal per se, just not generally synthesizable unless the argument is known static.
I am working on "stream_xbar.sv" to verify it formally. I found one bug that when two different sel_i port have same destination then ready_o of these port can't be high at a same time. For example, if "sel_i[0] = 2" and "sel_i[3] = 2" then "ready_o[0]" and "ready_o[3]" can't be high at same time.
Is this a bug or design intent?
We're making use of sync_wedge and thus sync in our design (specifically, it's used in the CLINT from Ariane). The naming used to be nicely prefixed (pulp_) to not have any conflicts, but the name sync is generic enough that we're getting naming conflicts when working with Amazon's F1 infrastructure.
We tried using pulp_sync instead but the interface changed so we had to tinker some and it means we need to keep a fork for little good reason.
Is there any chance you could rename this upstream or adopt a SV package to avoid such conflicts?
This is a feature request to extend the stream_join IP or provide the extended functionality in a separate IP.
Currently, the stream_join IP enforces:
all of the streams to be joined together
all input handshakes to occur simultaneously, i.e. an input stream is granted ready only after all input streams are valid
Conversely, we seek the following features:
dynamically select a subset of streams to be joined
allow input streams to be granted independently of each other
Feature (1) is similar to the functionality stream_fork_dynamic provides over stream_fork. The stream_fork IP is "specular" in its functionality to stream_join.
Right now there are a couple of ad-hoc implementations of the rand_stream protocol. This issue keeps track of the unification of those different implementations into one supported rand_stream_* class. CC #100
@meggiman I ran into another issue with the clock divider.
Following the description
// It is thus safe to statically tie the valid signal to logic high if
// we can guarantee, that the div_i value remains stable long enough (upper
// limit 2 output clock cycles).
I tied valid_i to 1 and connected div_i to a register which has a reset value 0.
That's when I noticed that after div_q = 0 is loaded, I'm not able to reconfigure the clock divider.
As far as I understood, it hangs in the WAIT_END_PERIOD state, because the following condition can never be satisfied.
For example:
We can set up an always block generating a new clk_o based on whether the counter is gated or a new value is requested. Then we can do something like:
I have developed a new version of shift_reg which has a valid flag for data to enable DC insert ICG for the internal datapath, the new version shift_reg is backward compatible with the older one and has a better power comuption. Is it welcomed to add it to this library?
Several IPs internally instantiate a more generic version, leaving unneeded ports tied or unconnected. To ensure that only the required logic is instantiated, cross-boundary optimisations and constant propagation are needed, putting a lot of weight on the tools, which often do not meet expectations.
Therefore, restructure the IPs that currently rely on wrappers in a more tool-friendly manner (i.e. using parameters). These IPs are
Some constants declared in the parameter list are not actual parameters that accept user inputs but require a fixed value (assigned as default value). A deviation from the required value can cause the module to behave in an undefined way. Such constants should not be a parameter but a localparam instead, to cause an elaboration-time error if the parameter value is changed at instantiation.
@zarubaf: Is there a reason pipe_reg_simple.sv is not in Bender.yml? And before putting it there (maybe in the 1.10 release?), would shift_reg not be a more appropriate name?
Hi I am a french intern in computer architecture at Université paris saclay and I work on the implementation of IBEX in a low power system.
I just started system verilog a week ago, so my understanding of it is quite poor. If the issue is not correct do not hesitate to close the issue.
For context : I recently changed my computer so I re-installed verilator from sources. Doing So broke many pieces of my system.
I am now getting errors like this when compiling:
src/pulp-platform.org__common_cells_1.28.0/src/lzc.sv:23:51: Static access to non-static task/function 'idx_width'
parameter int unsigned CNT_WIDTH = cf_math_pkg::idx_width(WIDTH)
I also get the same errors in the tcdm interconnect package.
At first I though I did something wrong but after reading the reference of system verilog I found that the :: is indeed reserved for static functions. And so the call to idx_width which is labelled as automatic is indeed illegal. (or at least that's what I am thinking with my small understanding of the language)
I just discovered there has been a very recent change in verilator : verilator/verilator#4072
My understanding is that calls to automatic functions need to be hierarchical for verilator to accept them.
I will just checkout to a branch of verilator that doesn't have the patch and see where it goes.
I am working on verifying the stream crossbar using formal verification. There is too much confusion regarding the stream_xbar.sv file. Is there any proper documentation available for the stream_xbar.sv file?
Is there a corresponding issue in the fpnew repo? As far as I know, this is not an issue with Ara, but rather on how the fpnew handles the vector execution of those instructions.
assrt2_stable_idx_o: // idx_o remains stable when there is no ready_i and valid_o is high
assert property (valid_o[i] && !ready_i[i] |=> $stable(idx_o[i]));
assrt3_stable_data_o: // data_o remains stable when there is no ready_i and valid_o is high
assert property (valid_o[i] && !ready_i[i] |=> $stable(data_o[i]));
These two assertions fail when OutSpillReg is set to 0. Shouldn't it be stable?
generate
for (genvar inp = 0; inp < NumInp ; inp++ )
assrt8_flush_with_ready_0: // when flush_i is asserted ready_o should be zero
assert property(flush_i |-> ready_o[inp]==0);
endgenerate
It passes for all other ready_o, but fails for ready_o[31].
Thanks for this great job, but I have get an error message when re-using some module with the fusesoc tool in a simple test project. Partial content of my core file is as bellow:
What I want is only the delta_counter module while as the whole library is added to my project, fusesoc can't find the assertions.svh file for stream_fifo_optimal_wrap module when run lint or simulation with verilator. The problem is resovled by adding the header file in the common_cells.core file as bellow:
CAPI=2:
name : pulp-platform.org::common_cells:1.26.0filesets:
rtl:
files:
- include/common_cells/registers.svh : {is_include_file : true, include_path : include}
- include/common_cells/assertions.svh : {is_include_file : true, include_path : include}# Source files grouped in levels. Files in level 0 have no dependencies on files in this package.# Files in level 1 only depend on files in level 0, files in level 2 on files in levels 1 and 0,# etc. Files within a level are ordered alphabetically.
- src/binary_to_gray.sv# ...
My question is :
whether the assertions.svh is excluded intentionally or not ?
and if the answer is yes, how to avoid this problem in other designs excepting modify the common_cells.core file locally ?
In the below assignment, the RHS being a genvar is 32-bits wide, while the LHS which is parameterized and need not be always of 32-bits wide. Thus the compiler throws a width mismatch error.
Hi Everyone,
I am running a system made up in part of the modules provided in this repo and the AXI one. Additionally, I use some of the IP provided by Xilinx.
To simulate everything, I run vsim with all Xilinx libraries mapped. Unfortunately, some of the Xilinx internal modules share names with the modules in this repo, for example the "counter". In that case, simulation fails to start with errors like
# ** Fatal: (vsim-3350) Generic "<protected>" has not been given a value.
# Time: 0 fs Iteration: 0 Protected: /tb_sort_stage/mem_delay/i_axi_delayer/i_stream_delay_aw/gen_delay/<protected> File: {MYXILINXINSTALL}/data/ip/xilinx/cic_compiler_v4_0/hdl/cic_compiler_v4_0_vh_rfs.vhd Line: 73
The easy fix to this in my case is to rename the counter module to something unique. I wonder if/how this could be fixed in a more principled approach?
Hey!
I have question about assertion in src/stream_xbar.sv:
for (genvar i = 0; unsigned'(i) < NumInp; i++) begin : gen_sel_assertions
assert property (@(posedge clk_i) (valid_i[i] |-> sel_i[i] < sel_oup_t'(NumOut))) else
$fatal(1, "Non-existing output is selected!");
end
Why do you use : sel_oup_t'(NumOut) if for example NumOut = 4 so sel_oup_t is logic[1:0] so result from this cast will be always 0. So (valid_i[i] |-> sel_i[i] < 0)
When downstream has backpressure, the flush function cannot work properly. so can we add the following sva property?
assupe property (
@(posedge clk_i) disable iff (!rst_ni)
flush_i |-> ready_i
) else $warning("Trying to flush when downstream not ready");
in lzc module the comment says:
/// If the input does not contain a zero, empty_o is asserted. Additionally cnt_o contains
/// the maximum number of zeros - 1.
if the WIDTH is power of 2, it works fine
but if the WIDTH is not the power of 2,i.e WIDTH is 29
when in_i is empty, cnt_o is zero instead of 29-1
because in the rtl
// if index is out of range
if (unsigned'(k) * 2 > WIDTH - 1) begin : g_out_of_range
assign sel_nodes[2 ** level - 1 + k] = 1'b0;
assign index_nodes[2 ** level - 1 + k] = '0; // why not assign index_nodes[2 ** level - 1 + k] = WIDTH-1;
end