Merge pull request #1551 from whitequark/manual-cell-operands

Clarify semantics of comb cells, in particular shifts
This commit is contained in:
Clifford Wolf 2019-12-05 08:24:24 -08:00 committed by GitHub
commit 7dece7955e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 43 deletions

View File

@ -2242,7 +2242,7 @@ gen_stmt:
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} opt_arg_list ';'{
ast_stack.pop_back();
ast_stack.pop_back();
};
gen_stmt_block:
@ -2413,19 +2413,19 @@ basic_expr:
append_attr($$, $2);
} |
basic_expr OP_SHL attr basic_expr {
$$ = new AstNode(AST_SHIFT_LEFT, $1, $4);
$$ = new AstNode(AST_SHIFT_LEFT, $1, new AstNode(AST_TO_UNSIGNED, $4));
append_attr($$, $3);
} |
basic_expr OP_SHR attr basic_expr {
$$ = new AstNode(AST_SHIFT_RIGHT, $1, $4);
$$ = new AstNode(AST_SHIFT_RIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4));
append_attr($$, $3);
} |
basic_expr OP_SSHL attr basic_expr {
$$ = new AstNode(AST_SHIFT_SLEFT, $1, $4);
$$ = new AstNode(AST_SHIFT_SLEFT, $1, new AstNode(AST_TO_UNSIGNED, $4));
append_attr($$, $3);
} |
basic_expr OP_SSHR attr basic_expr {
$$ = new AstNode(AST_SHIFT_SRIGHT, $1, $4);
$$ = new AstNode(AST_SHIFT_SRIGHT, $1, new AstNode(AST_TO_UNSIGNED, $4));
append_attr($$, $3);
} |
basic_expr '<' attr basic_expr {

View File

@ -783,6 +783,14 @@ namespace {
return v;
}
int param_bool(RTLIL::IdString name, bool expected)
{
int v = param_bool(name);
if (v != expected)
error(__LINE__);
return v;
}
void param_bits(RTLIL::IdString name, int width)
{
param(name);
@ -869,13 +877,23 @@ namespace {
return;
}
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) {
if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr))) {
param_bool(ID(A_SIGNED));
param_bool(ID(B_SIGNED), /*expected=*/false);
port(ID::A, param(ID(A_WIDTH)));
port(ID::B, param(ID(B_WIDTH)));
port(ID::Y, param(ID(Y_WIDTH)));
check_expected(/*check_matched_sign=*/false);
return;
}
if (cell->type.in(ID($shift), ID($shiftx))) {
param_bool(ID(A_SIGNED));
param_bool(ID(B_SIGNED));
port(ID::A, param(ID(A_WIDTH)));
port(ID::B, param(ID(B_WIDTH)));
port(ID::Y, param(ID(Y_WIDTH)));
check_expected(false);
check_expected(/*check_matched_sign=*/false);
return;
}
@ -957,7 +975,7 @@ namespace {
port(ID::A, param(ID(A_WIDTH)));
port(ID::B, param(ID(B_WIDTH)));
port(ID::Y, param(ID(Y_WIDTH)));
check_expected(false);
check_expected(/*check_matched_sign=*/false);
return;
}

View File

@ -65,6 +65,11 @@ Verilog & Cell Type \\
\label{tab:CellLib_unary}
\end{table}
For the unary cells that output a logical value ({\tt \$reduce\_and}, {\tt \$reduce\_or},
{\tt \$reduce\_xor}, {\tt \$reduce\_xnor}, {\tt \$reduce\_bool}, {\tt \$logic\_not}),
when the \B{Y\_WIDTH} parameter is greater than 1, the output is zero-extended,
and only the least significant bit varies.
Note that {\tt \$reduce\_or} and {\tt \$reduce\_bool} actually represent the same
logic function. But the HDL frontends generate them in different situations. A
{\tt \$reduce\_or} cell is generated when the prefix {\tt |} operator is being used. A
@ -97,41 +102,6 @@ The width of the output port \B{Y}.
Table~\ref{tab:CellLib_binary} lists all cells for binary RTL operators.
\subsection{Multiplexers}
Multiplexers are generated by the Verilog HDL frontend for {\tt
?:}-expressions. Multiplexers are also generated by the {\tt proc} pass to map the decision trees
from RTLIL::Process objects to logic.
The simplest multiplexer cell type is {\tt \$mux}. Cells of this type have a \B{WIDTH} parameter
and data inputs \B{A} and \B{B} and a data output \B{Y}, all of the specified width. This cell also
has a single bit control input \B{S}. If \B{S} is 0 the value from the \B{A} input is sent to
the output, if it is 1 the value from the \B{B} input is sent to the output. So the {\tt \$mux}
cell implements the function \lstinline[language=Verilog]; Y = S ? B : A;.
The {\tt \$pmux} cell is used to multiplex between many inputs using a one-hot select signal. Cells
of this type have a \B{WIDTH} and a \B{S\_WIDTH} parameter and inputs \B{A}, \B{B}, and \B{S} and
an output \B{Y}. The \B{S} input is \B{S\_WIDTH} bits wide. The \B{A} input and the output are both
\B{WIDTH} bits wide and the \B{B} input is \B{WIDTH}*\B{S\_WIDTH} bits wide. When all bits of
\B{S} are zero, the value from \B{A} input is sent to the output. If the $n$'th bit from \B{S} is
set, the value $n$'th \B{WIDTH} bits wide slice of the \B{B} input is sent to the output. When more
than one bit from \B{S} is set the output is undefined. Cells of this type are used to model
``parallel cases'' (defined by using the {\tt parallel\_case} attribute or detected by
an optimization).
The {\tt \$tribuf} cell is used to implement tristate logic. Cells of this type have a \B{WIDTH}
parameter and inputs \B{A} and \B{EN} and an output \B{Y}. The \B{A} input and \B{Y} output are
\B{WIDTH} bits wide, and the \B{EN} input is one bit wide. When \B{EN} is 0, the output \B{Y}
is not driven. When \B{EN} is 1, the value from \B{A} input is sent to the \B{Y} output. Therefore,
the {\tt \$tribuf} cell implements the function \lstinline[language=Verilog]; Y = EN ? A : 'bz;.
Behavioural code with cascaded {\tt if-then-else}- and {\tt case}-statements
usually results in trees of multiplexer cells. Many passes (from various
optimizations to FSM extraction) heavily depend on these multiplexer trees to
understand dependencies between signals. Therefore optimizations should not
break these multiplexer trees (e.g.~by replacing a multiplexer between a
calculated signal and a constant zero with an {\tt \$and} gate).
\begin{table}[t!]
\hfil
\begin{tabular}[t]{ll}
@ -175,6 +145,57 @@ Verilog & Cell Type \\
\label{tab:CellLib_binary}
\end{table}
The {\tt \$shl} and {\tt \$shr} cells implement logical shifts, whereas the {\tt \$sshl} and
{\tt \$sshr} cells implement arithmetic shifts. The {\tt \$shl} and {\tt \$sshl} cells implement
the same operation. All four of these cells interpret the second operand as unsigned, and require
\B{B\_SIGNED} to be zero.
Two additional shift operator cells are available that do not directly correspond to any operator
in Verilog, {\tt \$shift} and {\tt \$shiftx}. The {\tt \$shift} cell performs a right logical shift
if the second operand is positive (or unsigned), and a left logical shift if it is negative.
The {\tt \$shiftx} cell performs the same operation as the {\tt \$shift} cell, but the vacated bit
positions are filled with undef (x) bits, and corresponds to the Verilog indexed part-select expression.
For the binary cells that output a logical value ({\tt \$logic\_and}, {\tt \$logic\_or},
{\tt \$eqx}, {\tt \$nex}, {\tt \$lt}, {\tt \$le}, {\tt \$eq}, {\tt \$ne}, {\tt \$ge},
{\tt \$gt}), when the \B{Y\_WIDTH} parameter is greater than 1, the output is zero-extended,
and only the least significant bit varies.
\subsection{Multiplexers}
Multiplexers are generated by the Verilog HDL frontend for {\tt
?:}-expressions. Multiplexers are also generated by the {\tt proc} pass to map the decision trees
from RTLIL::Process objects to logic.
The simplest multiplexer cell type is {\tt \$mux}. Cells of this type have a \B{WIDTH} parameter
and data inputs \B{A} and \B{B} and a data output \B{Y}, all of the specified width. This cell also
has a single bit control input \B{S}. If \B{S} is 0 the value from the \B{A} input is sent to
the output, if it is 1 the value from the \B{B} input is sent to the output. So the {\tt \$mux}
cell implements the function \lstinline[language=Verilog]; Y = S ? B : A;.
The {\tt \$pmux} cell is used to multiplex between many inputs using a one-hot select signal. Cells
of this type have a \B{WIDTH} and a \B{S\_WIDTH} parameter and inputs \B{A}, \B{B}, and \B{S} and
an output \B{Y}. The \B{S} input is \B{S\_WIDTH} bits wide. The \B{A} input and the output are both
\B{WIDTH} bits wide and the \B{B} input is \B{WIDTH}*\B{S\_WIDTH} bits wide. When all bits of
\B{S} are zero, the value from \B{A} input is sent to the output. If the $n$'th bit from \B{S} is
set, the value $n$'th \B{WIDTH} bits wide slice of the \B{B} input is sent to the output. When more
than one bit from \B{S} is set the output is undefined. Cells of this type are used to model
``parallel cases'' (defined by using the {\tt parallel\_case} attribute or detected by
an optimization).
The {\tt \$tribuf} cell is used to implement tristate logic. Cells of this type have a \B{WIDTH}
parameter and inputs \B{A} and \B{EN} and an output \B{Y}. The \B{A} input and \B{Y} output are
\B{WIDTH} bits wide, and the \B{EN} input is one bit wide. When \B{EN} is 0, the output \B{Y}
is not driven. When \B{EN} is 1, the value from \B{A} input is sent to the \B{Y} output. Therefore,
the {\tt \$tribuf} cell implements the function \lstinline[language=Verilog]; Y = EN ? A : 'bz;.
Behavioural code with cascaded {\tt if-then-else}- and {\tt case}-statements
usually results in trees of multiplexer cells. Many passes (from various
optimizations to FSM extraction) heavily depend on these multiplexer trees to
understand dependencies between signals. Therefore optimizations should not
break these multiplexer trees (e.g.~by replacing a multiplexer between a
calculated signal and a constant zero with an {\tt \$and} gate).
\subsection{Registers}
D-Type Flip-Flops are represented by {\tt \$dff} cells. These cells have a clock port \B{CLK},