Respect \A_SIGNED for $shift
authorXiretza <xiretza@xiretza.xyz>
Fri, 3 Jul 2020 11:13:21 +0000 (13:13 +0200)
committerMarcelina Koƛcielnicka <mwk@0x04.net>
Tue, 18 Aug 2020 17:36:24 +0000 (19:36 +0200)
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).

backends/btor/btor.cc
backends/btor/test_cells.sh [changed mode: 0644->0755]
backends/verilog/verilog_backend.cc
kernel/calc.cc
kernel/satgen.cc
techlibs/common/simlib.v
techlibs/common/techmap.v

index e5da6c1e7e1ed2d3d9edcdf787e93f9f850b5b51..5abab8978c3e40be3ebf616b503c5ef641ef9822 100644 (file)
@@ -205,9 +205,8 @@ struct BtorWorker
                        if (cell->type.in(ID($xnor), ID($_XNOR_))) btor_op = "xnor";
                        log_assert(!btor_op.empty());
 
-                       int width = GetSize(cell->getPort(ID::Y));
-                       width = std::max(width, GetSize(cell->getPort(ID::A)));
-                       width = std::max(width, GetSize(cell->getPort(ID::B)));
+                       int width_ay = std::max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::Y)));
+                       int width = std::max(width_ay, GetSize(cell->getPort(ID::B)));
 
                        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;
@@ -224,11 +223,23 @@ struct BtorWorker
                        int sid = get_bv_sid(width);
                        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")
                        {
-                               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++;
                                btorf("%d srl %d %d %d\n", nid_r, sid, nid_a, nid_b);
 
@@ -248,9 +259,6 @@ struct BtorWorker
                        }
                        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++;
                                btorf("%d %s %d %d %d%s\n", nid, btor_op.c_str(), sid, nid_a, nid_b, getinfo(cell).c_str());
                        }
old mode 100644 (file)
new mode 100755 (executable)
index 3f07720..0a01193
@@ -6,7 +6,7 @@ rm -rf test_cells.tmp
 mkdir -p 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
        ../../../yosys -p "
@@ -19,7 +19,7 @@ for fn in test_*.il; do
                hierarchy -top main
                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
                echo "Check failed for ${fn%.il}."
                exit 1
index a0e677d138157338a39c76b0cda2522746bc6a69..372f68ea5cb6ade6e03bf3c67c37f6ad95d84bdf 100644 (file)
@@ -750,21 +750,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                f << stringf(" = ");
                if (cell->getParam(ID::B_SIGNED).as_bool())
                {
-                       f << stringf("$signed(");
-                       dump_sigspec(f, cell->getPort(ID::B));
-                       f << stringf(")");
+                       dump_cell_expr_port(f, cell, "B", true);
                        f << stringf(" < 0 ? ");
-                       dump_sigspec(f, cell->getPort(ID::A));
+                       dump_cell_expr_port(f, cell, "A", true);
                        f << stringf(" << - ");
                        dump_sigspec(f, cell->getPort(ID::B));
                        f << stringf(" : ");
-                       dump_sigspec(f, cell->getPort(ID::A));
+                       dump_cell_expr_port(f, cell, "A", true);
                        f << stringf(" >> ");
                        dump_sigspec(f, cell->getPort(ID::B));
                }
                else
                {
-                       dump_sigspec(f, cell->getPort(ID::A));
+                       dump_cell_expr_port(f, cell, "A", true);
                        f << stringf(" >> ");
                        dump_sigspec(f, cell->getPort(ID::B));
                }
index ae18809d3f62cdc20e9858f09475fd3c2c0af497..d54ccbc10c861c2cfea062869cad11321a374746 100644 (file)
@@ -275,10 +275,15 @@ RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const
        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;
-       BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction;
+       BigInteger offset = const2big(arg2, signed2, undef_bit_pos) * direction;
 
        if (result_len < 0)
                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++) {
                BigInteger pos = BigInteger(i) + offset;
                if (pos < 0)
-                       result.bits[i] = RTLIL::State::S0;
+                       result.bits[i] = vacant_bits;
                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
                        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;
        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 arg1_ext = arg1;
        extend_u0(arg1_ext, max(result_len, GetSize(arg1)), signed1);
-       return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
-}
-
-RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
-{
-       if (!signed1)
-               return const_shl(arg1, arg2, signed1, signed2, result_len);
-       return const_shift_worker(arg1, arg2, true, -1, result_len);
+       return const_shift_worker(arg1_ext, arg2, false, false, +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_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
 {
-       if (!signed1)
-               return const_shr(arg1, arg2, signed1, signed2, result_len);
-       return const_shift_worker(arg1, arg2, true, +1, result_len);
+       return const_shift_worker(arg1, arg2, signed1, false, -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)
+RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
 {
-       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;
+       return const_shift_worker(arg1, arg2, signed1, false, +1, 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)
index 73839d37a58a36b918a6b6b48997b38febdab519..2a54e78ec23a00e4a03b57a55f6d14526f1b702a 100644 (file)
@@ -522,7 +522,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
 
                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();
 
                while (y.size() < a.size())
@@ -555,7 +555,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
                        std::vector<int> undef_a_shifted;
 
                        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();
 
                        while (undef_y.size() < undef_a.size())
index 2660e6f152fdbaaa82f71c46fd187218d4dee77b..e9488402561344bdb13e6de56f67bcb15b5ce2af 100644 (file)
@@ -480,10 +480,18 @@ input [B_WIDTH-1:0] B;
 output [Y_WIDTH-1:0] Y;
 
 generate
-       if (B_SIGNED) begin:BLOCK1
-               assign Y = $signed(B) < 0 ? A << -B : A >> B;
-       end else begin:BLOCK2
-               assign Y = A >> B;
+       if (A_SIGNED) begin:BLOCK1
+               if (B_SIGNED) begin:BLOCK2
+                       assign Y = $signed(B) < 0 ? $signed(A) << -B : $signed(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
 endgenerate
 
index 9607302b70d01e341bf4de62f35717a5ef53f08b..03c27d49d9ecf42abf7c5cdd2808dd6740996df4 100644 (file)
@@ -141,6 +141,7 @@ module _90_shift_shiftx (A, B, Y);
        parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
 
        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
 `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 len = Y_WIDTH2 * ((entries+1)/2);
                        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;
                        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];
@@ -187,7 +188,8 @@ module _90_shift_shiftx (A, B, Y);
                        always @* begin
                                overflow = 0;
                                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_SIGNED) begin