mirror of https://github.com/YosysHQ/yosys.git
Respect \A_SIGNED for $shift
This reflects the behaviour of $shr/$shl, which sign-extend their A operands to the size of their output, then do a logical shift (shift in 0-bits).
This commit is contained in:
parent
22765ef0a5
commit
928fd40c2e
|
@ -205,9 +205,8 @@ struct BtorWorker
|
||||||
if (cell->type.in(ID($xnor), ID($_XNOR_))) btor_op = "xnor";
|
if (cell->type.in(ID($xnor), ID($_XNOR_))) btor_op = "xnor";
|
||||||
log_assert(!btor_op.empty());
|
log_assert(!btor_op.empty());
|
||||||
|
|
||||||
int width = GetSize(cell->getPort(ID::Y));
|
int width_ay = std::max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::Y)));
|
||||||
width = std::max(width, GetSize(cell->getPort(ID::A)));
|
int width = std::max(width_ay, GetSize(cell->getPort(ID::B)));
|
||||||
width = std::max(width, GetSize(cell->getPort(ID::B)));
|
|
||||||
|
|
||||||
bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false;
|
bool a_signed = cell->hasParam(ID::A_SIGNED) ? cell->getParam(ID::A_SIGNED).as_bool() : false;
|
||||||
bool b_signed = cell->hasParam(ID::B_SIGNED) ? cell->getParam(ID::B_SIGNED).as_bool() : false;
|
bool b_signed = cell->hasParam(ID::B_SIGNED) ? cell->getParam(ID::B_SIGNED).as_bool() : false;
|
||||||
|
@ -224,11 +223,23 @@ struct BtorWorker
|
||||||
int sid = get_bv_sid(width);
|
int sid = get_bv_sid(width);
|
||||||
int nid;
|
int nid;
|
||||||
|
|
||||||
|
int nid_a;
|
||||||
|
if (cell->type.in(ID($shl), ID($shr), ID($shift), ID($shiftx)) && a_signed && width_ay < width) {
|
||||||
|
// sign-extend A up to the width of Y
|
||||||
|
int nid_a_padded = get_sig_nid(cell->getPort(ID::A), width_ay, a_signed);
|
||||||
|
|
||||||
|
// zero-extend the rest
|
||||||
|
int zeroes = get_sig_nid(Const(0, width-width_ay));
|
||||||
|
nid_a = next_nid++;
|
||||||
|
btorf("%d concat %d %d %d\n", nid_a, sid, zeroes, nid_a_padded);
|
||||||
|
} else {
|
||||||
|
nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed);
|
||||||
|
|
||||||
if (btor_op == "shift")
|
if (btor_op == "shift")
|
||||||
{
|
{
|
||||||
int nid_a = get_sig_nid(cell->getPort(ID::A), width, false);
|
|
||||||
int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed);
|
|
||||||
|
|
||||||
int nid_r = next_nid++;
|
int nid_r = next_nid++;
|
||||||
btorf("%d srl %d %d %d\n", nid_r, sid, nid_a, nid_b);
|
btorf("%d srl %d %d %d\n", nid_r, sid, nid_a, nid_b);
|
||||||
|
|
||||||
|
@ -248,9 +259,6 @@ struct BtorWorker
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
|
|
||||||
int nid_b = get_sig_nid(cell->getPort(ID::B), width, b_signed);
|
|
||||||
|
|
||||||
nid = next_nid++;
|
nid = next_nid++;
|
||||||
btorf("%d %s %d %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str());
|
btorf("%d %s %d %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str());
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ rm -rf test_cells.tmp
|
||||||
mkdir -p test_cells.tmp
|
mkdir -p test_cells.tmp
|
||||||
cd test_cells.tmp
|
cd test_cells.tmp
|
||||||
|
|
||||||
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod /$divfloor /$modfloor'
|
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod /$divfloor /$modfloor /$shiftx'
|
||||||
|
|
||||||
for fn in test_*.il; do
|
for fn in test_*.il; do
|
||||||
../../../yosys -p "
|
../../../yosys -p "
|
||||||
|
@ -19,7 +19,7 @@ for fn in test_*.il; do
|
||||||
hierarchy -top main
|
hierarchy -top main
|
||||||
write_btor ${fn%.il}.btor
|
write_btor ${fn%.il}.btor
|
||||||
"
|
"
|
||||||
boolectormc -kmax 1 --trace-gen --stop-first -v ${fn%.il}.btor > ${fn%.il}.out
|
btormc -kmax 1 --trace-gen --stop-first -v ${fn%.il}.btor > ${fn%.il}.out
|
||||||
if grep " SATISFIABLE" ${fn%.il}.out; then
|
if grep " SATISFIABLE" ${fn%.il}.out; then
|
||||||
echo "Check failed for ${fn%.il}."
|
echo "Check failed for ${fn%.il}."
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -750,21 +750,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
||||||
f << stringf(" = ");
|
f << stringf(" = ");
|
||||||
if (cell->getParam(ID::B_SIGNED).as_bool())
|
if (cell->getParam(ID::B_SIGNED).as_bool())
|
||||||
{
|
{
|
||||||
f << stringf("$signed(");
|
dump_cell_expr_port(f, cell, "B", true);
|
||||||
dump_sigspec(f, cell->getPort(ID::B));
|
|
||||||
f << stringf(")");
|
|
||||||
f << stringf(" < 0 ? ");
|
f << stringf(" < 0 ? ");
|
||||||
dump_sigspec(f, cell->getPort(ID::A));
|
dump_cell_expr_port(f, cell, "A", true);
|
||||||
f << stringf(" << - ");
|
f << stringf(" << - ");
|
||||||
dump_sigspec(f, cell->getPort(ID::B));
|
dump_sigspec(f, cell->getPort(ID::B));
|
||||||
f << stringf(" : ");
|
f << stringf(" : ");
|
||||||
dump_sigspec(f, cell->getPort(ID::A));
|
dump_cell_expr_port(f, cell, "A", true);
|
||||||
f << stringf(" >> ");
|
f << stringf(" >> ");
|
||||||
dump_sigspec(f, cell->getPort(ID::B));
|
dump_sigspec(f, cell->getPort(ID::B));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dump_sigspec(f, cell->getPort(ID::A));
|
dump_cell_expr_port(f, cell, "A", true);
|
||||||
f << stringf(" >> ");
|
f << stringf(" >> ");
|
||||||
dump_sigspec(f, cell->getPort(ID::B));
|
dump_sigspec(f, cell->getPort(ID::B));
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,10 +275,15 @@ RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
|
// Shift `arg1` by `arg2` bits.
|
||||||
|
// If `direction` is +1, `arg1` is shifted right by `arg2` bits; if `direction` is -1, `arg1` is shifted left by `arg2` bits.
|
||||||
|
// If `signed2` is true, `arg2` is interpreted as a signed integer; a negative `arg2` will cause a shift in the opposite direction.
|
||||||
|
// Any required bits outside the bounds of `arg1` are padded with `vacant_bits` unless `sign_ext` is true, in which case any bits outside the left
|
||||||
|
// bounds are filled with the leftmost bit of `arg1` (arithmetic shift).
|
||||||
|
static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, bool signed2, int direction, int result_len, RTLIL::State vacant_bits = RTLIL::State::S0)
|
||||||
{
|
{
|
||||||
int undef_bit_pos = -1;
|
int undef_bit_pos = -1;
|
||||||
BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction;
|
BigInteger offset = const2big(arg2, signed2, undef_bit_pos) * direction;
|
||||||
|
|
||||||
if (result_len < 0)
|
if (result_len < 0)
|
||||||
result_len = arg1.bits.size();
|
result_len = arg1.bits.size();
|
||||||
|
@ -290,9 +295,9 @@ static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Co
|
||||||
for (int i = 0; i < result_len; i++) {
|
for (int i = 0; i < result_len; i++) {
|
||||||
BigInteger pos = BigInteger(i) + offset;
|
BigInteger pos = BigInteger(i) + offset;
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
result.bits[i] = RTLIL::State::S0;
|
result.bits[i] = vacant_bits;
|
||||||
else if (pos >= BigInteger(int(arg1.bits.size())))
|
else if (pos >= BigInteger(int(arg1.bits.size())))
|
||||||
result.bits[i] = sign_ext ? arg1.bits.back() : RTLIL::State::S0;
|
result.bits[i] = sign_ext ? arg1.bits.back() : vacant_bits;
|
||||||
else
|
else
|
||||||
result.bits[i] = arg1.bits[pos.toInt()];
|
result.bits[i] = arg1.bits[pos.toInt()];
|
||||||
}
|
}
|
||||||
|
@ -304,61 +309,36 @@ RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2
|
||||||
{
|
{
|
||||||
RTLIL::Const arg1_ext = arg1;
|
RTLIL::Const arg1_ext = arg1;
|
||||||
extend_u0(arg1_ext, result_len, signed1);
|
extend_u0(arg1_ext, result_len, signed1);
|
||||||
return const_shift_worker(arg1_ext, arg2, false, -1, result_len);
|
return const_shift_worker(arg1_ext, arg2, false, false, -1, result_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
|
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
|
||||||
{
|
{
|
||||||
RTLIL::Const arg1_ext = arg1;
|
RTLIL::Const arg1_ext = arg1;
|
||||||
extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
|
extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
|
||||||
return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
|
return const_shift_worker(arg1_ext, arg2, false, false, +1, result_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
|
||||||
{
|
{
|
||||||
if (!signed1)
|
return const_shift_worker(arg1, arg2, signed1, false, -1, result_len);
|
||||||
return const_shl(arg1, arg2, signed1, signed2, result_len);
|
|
||||||
return const_shift_worker(arg1, arg2, true, -1, result_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
|
||||||
{
|
{
|
||||||
if (!signed1)
|
return const_shift_worker(arg1, arg2, signed1, false, +1, result_len);
|
||||||
return const_shr(arg1, arg2, signed1, signed2, result_len);
|
|
||||||
return const_shift_worker(arg1, arg2, true, +1, result_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static RTLIL::Const const_shift_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len, RTLIL::State other_bits)
|
|
||||||
{
|
|
||||||
int undef_bit_pos = -1;
|
|
||||||
BigInteger offset = const2big(arg2, signed2, undef_bit_pos);
|
|
||||||
|
|
||||||
if (result_len < 0)
|
|
||||||
result_len = arg1.bits.size();
|
|
||||||
|
|
||||||
RTLIL::Const result(RTLIL::State::Sx, result_len);
|
|
||||||
if (undef_bit_pos >= 0)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
for (int i = 0; i < result_len; i++) {
|
|
||||||
BigInteger pos = BigInteger(i) + offset;
|
|
||||||
if (pos < 0 || pos >= BigInteger(int(arg1.bits.size())))
|
|
||||||
result.bits[i] = other_bits;
|
|
||||||
else
|
|
||||||
result.bits[i] = arg1.bits[pos.toInt()];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||||
{
|
{
|
||||||
return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::S0);
|
RTLIL::Const arg1_ext = arg1;
|
||||||
|
extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
|
||||||
|
return const_shift_worker(arg1_ext, arg2, false, signed2, +1, result_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len)
|
||||||
{
|
{
|
||||||
return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::Sx);
|
return const_shift_worker(arg1, arg2, false, signed2, +1, result_len, RTLIL::State::Sx);
|
||||||
}
|
}
|
||||||
|
|
||||||
RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
|
||||||
|
|
|
@ -522,7 +522,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
||||||
|
|
||||||
int extend_bit = ez->CONST_FALSE;
|
int extend_bit = ez->CONST_FALSE;
|
||||||
|
|
||||||
if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool())
|
if (cell->parameters[ID::A_SIGNED].as_bool())
|
||||||
extend_bit = a.back();
|
extend_bit = a.back();
|
||||||
|
|
||||||
while (y.size() < a.size())
|
while (y.size() < a.size())
|
||||||
|
@ -555,7 +555,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
||||||
std::vector<int> undef_a_shifted;
|
std::vector<int> undef_a_shifted;
|
||||||
|
|
||||||
extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE;
|
extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE;
|
||||||
if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool())
|
if (cell->parameters[ID::A_SIGNED].as_bool())
|
||||||
extend_bit = undef_a.back();
|
extend_bit = undef_a.back();
|
||||||
|
|
||||||
while (undef_y.size() < undef_a.size())
|
while (undef_y.size() < undef_a.size())
|
||||||
|
|
|
@ -480,10 +480,18 @@ input [B_WIDTH-1:0] B;
|
||||||
output [Y_WIDTH-1:0] Y;
|
output [Y_WIDTH-1:0] Y;
|
||||||
|
|
||||||
generate
|
generate
|
||||||
if (B_SIGNED) begin:BLOCK1
|
if (A_SIGNED) begin:BLOCK1
|
||||||
assign Y = $signed(B) < 0 ? A << -B : A >> B;
|
if (B_SIGNED) begin:BLOCK2
|
||||||
end else begin:BLOCK2
|
assign Y = $signed(B) < 0 ? $signed(A) << -B : $signed(A) >> B;
|
||||||
assign Y = A >> B;
|
end else begin:BLOCK3
|
||||||
|
assign Y = $signed(A) >> B;
|
||||||
|
end
|
||||||
|
end else begin:BLOCK4
|
||||||
|
if (B_SIGNED) begin:BLOCK5
|
||||||
|
assign Y = $signed(B) < 0 ? A << -B : A >> B;
|
||||||
|
end else begin:BLOCK6
|
||||||
|
assign Y = A >> B;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
endgenerate
|
endgenerate
|
||||||
|
|
||||||
|
|
|
@ -141,6 +141,7 @@ module _90_shift_shiftx (A, B, Y);
|
||||||
parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
|
parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
|
||||||
|
|
||||||
localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx;
|
localparam extbit = _TECHMAP_CELLTYPE_ == "$shift" ? 1'b0 : 1'bx;
|
||||||
|
wire a_padding = _TECHMAP_CELLTYPE_ == "$shiftx" ? extbit : (A_SIGNED ? A[A_WIDTH-1] : 1'b0);
|
||||||
|
|
||||||
generate
|
generate
|
||||||
`ifndef NO_LSB_FIRST_SHIFT_SHIFTX
|
`ifndef NO_LSB_FIRST_SHIFT_SHIFTX
|
||||||
|
@ -160,7 +161,7 @@ module _90_shift_shiftx (A, B, Y);
|
||||||
localparam entries = (A_WIDTH+Y_WIDTH-1)/Y_WIDTH2;
|
localparam entries = (A_WIDTH+Y_WIDTH-1)/Y_WIDTH2;
|
||||||
localparam len = Y_WIDTH2 * ((entries+1)/2);
|
localparam len = Y_WIDTH2 * ((entries+1)/2);
|
||||||
wire [len-1:0] AA;
|
wire [len-1:0] AA;
|
||||||
wire [(A_WIDTH+Y_WIDTH2+Y_WIDTH-1)-1:0] Apad = {{(Y_WIDTH2+Y_WIDTH-1){extbit}}, A};
|
wire [(A_WIDTH+Y_WIDTH2+Y_WIDTH-1)-1:0] Apad = {{(Y_WIDTH2+Y_WIDTH-1){a_padding}}, A};
|
||||||
genvar i;
|
genvar i;
|
||||||
for (i = 0; i < A_WIDTH; i=i+Y_WIDTH2*2)
|
for (i = 0; i < A_WIDTH; i=i+Y_WIDTH2*2)
|
||||||
assign AA[i/2 +: Y_WIDTH2] = B[CLOG2_Y_WIDTH] ? Apad[i+Y_WIDTH2 +: Y_WIDTH2] : Apad[i +: Y_WIDTH2];
|
assign AA[i/2 +: Y_WIDTH2] = B[CLOG2_Y_WIDTH] ? Apad[i+Y_WIDTH2 +: Y_WIDTH2] : Apad[i +: Y_WIDTH2];
|
||||||
|
@ -187,7 +188,8 @@ module _90_shift_shiftx (A, B, Y);
|
||||||
always @* begin
|
always @* begin
|
||||||
overflow = 0;
|
overflow = 0;
|
||||||
buffer = {WIDTH{extbit}};
|
buffer = {WIDTH{extbit}};
|
||||||
buffer[`MAX(A_WIDTH, Y_WIDTH)-1:0] = A;
|
buffer[Y_WIDTH-1:0] = {Y_WIDTH{a_padding}};
|
||||||
|
buffer[A_WIDTH-1:0] = A;
|
||||||
|
|
||||||
if (B_WIDTH > BB_WIDTH) begin
|
if (B_WIDTH > BB_WIDTH) begin
|
||||||
if (B_SIGNED) begin
|
if (B_SIGNED) begin
|
||||||
|
|
Loading…
Reference in New Issue