2016-07-24 06:59:57 -05:00
/*
* yosys - - Yosys Open SYnthesis Suite
*
2021-06-07 17:39:36 -05:00
* Copyright ( C ) 2012 Claire Xenia Wolf < claire @ yosyshq . com >
2016-07-24 06:59:57 -05:00
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
*
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
*
*/
# include "kernel/celledges.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
2016-07-24 10:21:53 -05:00
void bitwise_unary_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
2016-07-24 06:59:57 -05:00
{
2020-04-02 11:51:32 -05:00
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
int y_width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2016-07-24 06:59:57 -05:00
for ( int i = 0 ; i < y_width ; i + + )
{
if ( i < a_width )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , i , ID : : Y , i , - 1 ) ;
2016-07-24 06:59:57 -05:00
else if ( is_signed & & a_width > 0 )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , a_width - 1 , ID : : Y , i , - 1 ) ;
2016-07-24 06:59:57 -05:00
}
}
2016-07-24 10:21:53 -05:00
void bitwise_binary_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
2016-07-24 06:59:57 -05:00
{
2020-04-02 11:51:32 -05:00
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
int b_width = GetSize ( cell - > getPort ( ID : : B ) ) ;
int y_width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2016-07-24 06:59:57 -05:00
2019-08-10 05:24:16 -05:00
if ( cell - > type = = ID ( $ and ) & & ! is_signed ) {
2016-07-24 06:59:57 -05:00
if ( a_width > b_width )
a_width = b_width ;
else
b_width = a_width ;
}
for ( int i = 0 ; i < y_width ; i + + )
{
if ( i < a_width )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , i , ID : : Y , i , - 1 ) ;
2016-07-24 06:59:57 -05:00
else if ( is_signed & & a_width > 0 )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , a_width - 1 , ID : : Y , i , - 1 ) ;
2016-07-24 06:59:57 -05:00
if ( i < b_width )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : B , i , ID : : Y , i , - 1 ) ;
2016-07-24 06:59:57 -05:00
else if ( is_signed & & b_width > 0 )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : B , b_width - 1 , ID : : Y , i , - 1 ) ;
2016-07-24 10:21:53 -05:00
}
}
void arith_neg_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
{
2020-04-02 11:51:32 -05:00
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
int y_width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2016-07-24 10:21:53 -05:00
if ( is_signed & & a_width = = 1 )
y_width = std : : min ( y_width , 1 ) ;
for ( int i = 0 ; i < y_width ; i + + )
for ( int k = 0 ; k < = i & & k < a_width ; k + + )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , k , ID : : Y , i , - 1 ) ;
2016-07-24 10:21:53 -05:00
}
void arith_binary_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
{
2020-04-02 11:51:32 -05:00
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
int b_width = GetSize ( cell - > getPort ( ID : : B ) ) ;
int y_width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2016-07-24 10:21:53 -05:00
2019-08-10 05:24:16 -05:00
if ( ! is_signed & & cell - > type ! = ID ( $ sub ) ) {
2016-07-24 10:21:53 -05:00
int ab_width = std : : max ( a_width , b_width ) ;
y_width = std : : min ( y_width , ab_width + 1 ) ;
}
for ( int i = 0 ; i < y_width ; i + + )
{
for ( int k = 0 ; k < = i ; k + + )
{
if ( k < a_width )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , k , ID : : Y , i , - 1 ) ;
2016-07-24 10:21:53 -05:00
if ( k < b_width )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : B , k , ID : : Y , i , - 1 ) ;
2016-07-24 10:21:53 -05:00
}
}
}
void reduce_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
{
2020-04-02 11:51:32 -05:00
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
2016-07-24 10:21:53 -05:00
for ( int i = 0 ; i < a_width ; i + + )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , i , ID : : Y , 0 , - 1 ) ;
2016-07-24 10:21:53 -05:00
}
void compare_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
{
2020-04-02 11:51:32 -05:00
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
int b_width = GetSize ( cell - > getPort ( ID : : B ) ) ;
2016-07-24 10:21:53 -05:00
for ( int i = 0 ; i < a_width ; i + + )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , i , ID : : Y , 0 , - 1 ) ;
2016-07-24 10:21:53 -05:00
for ( int i = 0 ; i < b_width ; i + + )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : B , i , ID : : Y , 0 , - 1 ) ;
2016-07-24 10:21:53 -05:00
}
void mux_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
{
2020-04-02 11:51:32 -05:00
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
int b_width = GetSize ( cell - > getPort ( ID : : B ) ) ;
int s_width = GetSize ( cell - > getPort ( ID : : S ) ) ;
2016-07-24 10:21:53 -05:00
for ( int i = 0 ; i < a_width ; i + + )
{
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : A , i , ID : : Y , i , - 1 ) ;
2016-07-24 10:21:53 -05:00
for ( int k = i ; k < b_width ; k + = a_width )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : B , k , ID : : Y , i , - 1 ) ;
2016-07-24 10:21:53 -05:00
for ( int k = 0 ; k < s_width ; k + + )
2020-04-02 11:51:32 -05:00
db - > add_edge ( cell , ID : : S , k , ID : : Y , i , - 1 ) ;
2016-07-24 06:59:57 -05:00
}
}
2022-01-24 09:02:29 -06:00
void bmux_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
{
int width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
int s_width = GetSize ( cell - > getPort ( ID : : S ) ) ;
for ( int i = 0 ; i < width ; i + + )
{
for ( int k = i ; k < a_width ; k + = width )
db - > add_edge ( cell , ID : : A , k , ID : : Y , i , - 1 ) ;
for ( int k = 0 ; k < s_width ; k + + )
db - > add_edge ( cell , ID : : S , k , ID : : Y , i , - 1 ) ;
}
}
void demux_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
{
int width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
int s_width = GetSize ( cell - > getPort ( ID : : S ) ) ;
for ( int i = 0 ; i < width ; i + + )
{
db - > add_edge ( cell , ID : : A , i % a_width , ID : : Y , i , - 1 ) ;
for ( int k = 0 ; k < s_width ; k + + )
db - > add_edge ( cell , ID : : S , k , ID : : Y , i , - 1 ) ;
}
}
2023-10-02 09:06:26 -05:00
void shift_op ( AbstractCellEdgesDatabase * db , RTLIL : : Cell * cell )
{
2023-10-02 11:32:53 -05:00
bool is_signed = cell - > getParam ( ID : : A_SIGNED ) . as_bool ( ) ;
2023-10-02 10:29:09 -05:00
int a_width = GetSize ( cell - > getPort ( ID : : A ) ) ;
2023-10-02 09:06:26 -05:00
int b_width = GetSize ( cell - > getPort ( ID : : B ) ) ;
2023-10-02 10:29:09 -05:00
int y_width = GetSize ( cell - > getPort ( ID : : Y ) ) ;
2023-10-02 09:06:26 -05:00
2023-10-02 11:32:53 -05:00
// how far the maximum value of B is able to shift
int b_range = ( 1 < < b_width ) - 1 ;
// highest position of Y that can change with the value of B
int b_range_upper ;
// 1 + highest position of A that can be moved to Y[i]
int a_range_upper ;
// lowest position of A that can be moved to Y[i]
int a_range_lower ;
2023-10-02 09:06:26 -05:00
2023-10-02 11:32:53 -05:00
for ( int i = 0 ; i < y_width ; i + + ) {
2023-10-02 09:06:26 -05:00
if ( cell - > type . in ( ID ( $ shl ) , ID ( $ sshl ) ) ) {
2023-10-02 11:32:53 -05:00
// << and <<<
b_range_upper = a_width + b_range ;
if ( is_signed ) b_range_upper - = 1 ;
a_range_lower = max ( 0 , i - b_range ) ;
a_range_upper = min ( i + 1 , a_width ) ;
} else if ( cell - > type . in ( ID ( $ shr ) , ID ( $ sshr ) ) ) {
// >> and >>>
b_range_upper = a_width ;
a_range_lower = min ( i , a_width - 1 ) ; // technically the min is unneccessary as b_range_upper check already skips any i >= a_width, but let's leave the logic in since this is hard enough
a_range_upper = min ( i + 1 + b_range , a_width ) ;
} else if ( cell - > type . in ( ID ( $ shift ) , ID ( $ shiftx ) ) ) {
// can go both ways depending on sign of B
// 2's complement range is different depending on direction
int b_range_left = ( 1 < < ( b_width - 1 ) ) ;
int b_range_right = ( 1 < < ( b_width - 1 ) ) - 1 ;
b_range_upper = a_width + b_range_left ;
a_range_lower = max ( 0 , i - b_range_left ) ;
a_range_upper = min ( i + 1 + b_range_right , a_width ) ;
2023-10-02 09:06:26 -05:00
}
2023-10-02 11:32:53 -05:00
if ( i < b_range_upper ) {
for ( int k = a_range_lower ; k < a_range_upper ; k + + )
2023-10-02 09:06:26 -05:00
db - > add_edge ( cell , ID : : A , k , ID : : Y , i , - 1 ) ;
2023-10-02 11:32:53 -05:00
} else {
// the only possible influence value is sign extension
if ( is_signed )
db - > add_edge ( cell , ID : : A , a_width - 1 , ID : : Y , i , - 1 ) ;
}
for ( int k = 0 ; k < b_width ; k + + ) {
if ( cell - > type . in ( ID ( $ shl ) , ID ( $ sshl ) ) & & a_width = = 1 & & is_signed ) {
int skip = ( 1 < < ( k + 1 ) ) ;
int base = skip - 1 ;
if ( i % skip ! = base )
db - > add_edge ( cell , ID : : B , k , ID : : Y , i , - 1 ) ;
} else if ( cell - > type . in ( ID ( $ shr ) , ID ( $ sshr ) ) & & is_signed ) {
2023-10-16 06:29:47 -05:00
bool shift_in_bulk = i < a_width - 1 ;
// can we jump into the ambient x-bits by toggling B[k]?
bool x_jump = ( ( ( y_width - i ) & ( ( 1 < < ( k + 1 ) ) - 1 ) ) ! = 0 \
& & ( ( ( y_width - i ) & ~ ( 1 < < k ) ) < ( 1 < < b_width ) ) ) ;
if ( shift_in_bulk | | ( cell - > type = = ID ( $ shr ) & & x_jump ) )
2023-10-02 11:32:53 -05:00
db - > add_edge ( cell , ID : : B , k , ID : : Y , i , - 1 ) ;
} else {
2023-10-16 06:29:47 -05:00
if ( i < a_width )
db - > add_edge ( cell , ID : : B , k , ID : : Y , i , - 1 ) ;
2023-10-02 11:32:53 -05:00
}
}
2023-10-02 09:06:26 -05:00
}
}
2016-07-24 06:59:57 -05:00
PRIVATE_NAMESPACE_END
2016-07-25 09:39:25 -05:00
bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase : : add_edges_from_cell ( RTLIL : : Cell * cell )
2016-07-24 06:59:57 -05:00
{
2019-08-10 05:24:16 -05:00
if ( cell - > type . in ( ID ( $ not ) , ID ( $ pos ) ) ) {
2016-07-24 10:21:53 -05:00
bitwise_unary_op ( this , cell ) ;
2016-07-24 06:59:57 -05:00
return true ;
}
2019-08-10 05:24:16 -05:00
if ( cell - > type . in ( ID ( $ and ) , ID ( $ or ) , ID ( $ xor ) , ID ( $ xnor ) ) ) {
2016-07-24 10:21:53 -05:00
bitwise_binary_op ( this , cell ) ;
2016-07-24 06:59:57 -05:00
return true ;
}
2019-08-10 05:24:16 -05:00
if ( cell - > type = = ID ( $ neg ) ) {
2016-07-24 10:21:53 -05:00
arith_neg_op ( this , cell ) ;
return true ;
}
2019-08-10 05:24:16 -05:00
if ( cell - > type . in ( ID ( $ add ) , ID ( $ sub ) ) ) {
2016-07-24 10:21:53 -05:00
arith_binary_op ( this , cell ) ;
return true ;
}
2019-08-10 05:24:16 -05:00
if ( cell - > type . in ( ID ( $ reduce_and ) , ID ( $ reduce_or ) , ID ( $ reduce_xor ) , ID ( $ reduce_xnor ) , ID ( $ reduce_bool ) , ID ( $ logic_not ) ) ) {
2016-07-24 10:21:53 -05:00
reduce_op ( this , cell ) ;
return true ;
}
2023-10-02 09:06:26 -05:00
if ( cell - > type . in ( ID ( $ shl ) , ID ( $ shr ) , ID ( $ sshl ) , ID ( $ sshr ) , ID ( $ shift ) , ID ( $ shiftx ) ) ) {
shift_op ( this , cell ) ;
return true ;
}
2016-07-24 10:21:53 -05:00
2019-08-10 05:24:16 -05:00
if ( cell - > type . in ( ID ( $ lt ) , ID ( $ le ) , ID ( $ eq ) , ID ( $ ne ) , ID ( $ eqx ) , ID ( $ nex ) , ID ( $ ge ) , ID ( $ gt ) ) ) {
2016-07-24 10:21:53 -05:00
compare_op ( this , cell ) ;
return true ;
}
2019-08-10 05:24:16 -05:00
if ( cell - > type . in ( ID ( $ mux ) , ID ( $ pmux ) ) ) {
2016-07-24 10:21:53 -05:00
mux_op ( this , cell ) ;
return true ;
}
2022-01-24 09:02:29 -06:00
if ( cell - > type = = ID ( $ bmux ) ) {
bmux_op ( this , cell ) ;
return true ;
}
if ( cell - > type = = ID ( $ demux ) ) {
demux_op ( this , cell ) ;
return true ;
}
2023-10-02 09:06:26 -05:00
// FIXME: $mul $div $mod $divfloor $modfloor $pow $slice $concat $bweqx
// FIXME: $lut $sop $alu $lcu $macc $fa $logic_and $logic_or $bwmux
// FIXME: $_BUF_ $_NOT_ $_AND_ $_NAND_ $_OR_ $_NOR_ $_XOR_ $_XNOR_ $_ANDNOT_ $_ORNOT_
// FIXME: $_MUX_ $_NMUX_ $_MUX4_ $_MUX8_ $_MUX16_ $_AOI3_ $_OAI3_ $_AOI4_ $_OAI4_
// FIXME: $specify2 $specify3 $specrule ???
// FIXME: $equiv $set_tag $get_tag $overwrite_tag $original_tag
if ( cell - > type . in ( ID ( $ assert ) , ID ( $ assume ) , ID ( $ live ) , ID ( $ fair ) , ID ( $ cover ) , ID ( $ initstate ) , ID ( $ anyconst ) , ID ( $ anyseq ) , ID ( $ allconst ) , ID ( $ allseq ) ) )
return true ; // no-op: these have either no inputs or no outputs
2016-07-24 10:21:53 -05:00
2016-07-24 06:59:57 -05:00
return false ;
}