Improved sat generator and sat_solve pass
authorClifford Wolf <clifford@clifford.at>
Fri, 7 Jun 2013 12:37:33 +0000 (14:37 +0200)
committerClifford Wolf <clifford@clifford.at>
Fri, 7 Jun 2013 12:37:33 +0000 (14:37 +0200)
kernel/satgen.h
libs/ezsat/ezsat.cc
libs/ezsat/ezsat.h
libs/ezsat/puzzle3d.cc
passes/sat/example.ys
passes/sat/sat_solve.cc

index 500c3f1053dd710f1f9d14e56bd93930b5950aaa..7535c75320b7eb5f943c40f777a4f920ac8afe48 100644 (file)
@@ -86,14 +86,6 @@ struct SatGen
        // cell_types.insert("$shr");
        // cell_types.insert("$sshl");
        // cell_types.insert("$sshr");
-       // cell_types.insert("$lt");
-       // cell_types.insert("$le");
-       // cell_types.insert("$eq");
-       // cell_types.insert("$ne");
-       // cell_types.insert("$ge");
-       // cell_types.insert("$gt");
-       // cell_types.insert("$add");
-       // cell_types.insert("$sub");
        // cell_types.insert("$mul");
        // cell_types.insert("$div");
        // cell_types.insert("$mod");
@@ -104,19 +96,45 @@ struct SatGen
        // cell_types.insert("$pmux");
        // cell_types.insert("$safe_pmux");
 
+       void extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, RTLIL::Cell *cell)
+       {
+               bool is_signed_a = false, is_signed_b = false;
+               if (cell->parameters.count("\\A_SIGNED") > 0)
+                       is_signed_a = cell->parameters["\\A_SIGNED"].as_bool();
+               if (cell->parameters.count("\\B_SIGNED") > 0)
+                       is_signed_b = cell->parameters["\\B_SIGNED"].as_bool();
+               while (vec_a.size() < vec_b.size())
+                       vec_a.push_back(is_signed_a && vec_a.size() > 0 ? vec_a.back() : ez->FALSE);
+               while (vec_b.size() < vec_a.size())
+                       vec_b.push_back(is_signed_b && vec_b.size() > 0 ? vec_b.back() : ez->FALSE);
+       }
+
+       void extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, std::vector<int> &vec_y, RTLIL::Cell *cell)
+       {
+               extendSignalWidth(vec_a, vec_b, cell);
+               while (vec_y.size() < vec_a.size())
+                       vec_y.push_back(ez->literal());
+       }
+
        virtual void importCell(RTLIL::Cell *cell)
        {
                if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_" ||
-                               cell->type == "$and" || cell->type == "$or" || cell->type == "$xor") {
+                               cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" ||
+                               cell->type == "$add" || cell->type == "$sub") {
                        std::vector<int> a = importSigSpec(cell->connections.at("\\A"));
                        std::vector<int> b = importSigSpec(cell->connections.at("\\B"));
                        std::vector<int> y = importSigSpec(cell->connections.at("\\Y"));
+                       extendSignalWidth(a, b, y, cell);
                        if (cell->type == "$and" || cell->type == "$_AND_")
                                ez->assume(ez->vec_eq(ez->vec_and(a, b), y));
                        if (cell->type == "$or" || cell->type == "$_OR_")
                                ez->assume(ez->vec_eq(ez->vec_or(a, b), y));
                        if (cell->type == "$xor" || cell->type == "$_XOR")
                                ez->assume(ez->vec_eq(ez->vec_xor(a, b), y));
+                       if (cell->type == "$add")
+                               ez->assume(ez->vec_eq(ez->vec_add(a, b), y));
+                       if (cell->type == "$sub")
+                               ez->assume(ez->vec_eq(ez->vec_sub(a, b), y));
                } else
                if (cell->type == "$_INV_" || cell->type == "$not") {
                        std::vector<int> a = importSigSpec(cell->connections.at("\\A"));
@@ -129,6 +147,25 @@ struct SatGen
                        std::vector<int> s = importSigSpec(cell->connections.at("\\S"));
                        std::vector<int> y = importSigSpec(cell->connections.at("\\Y"));
                        ez->assume(ez->vec_eq(ez->vec_ite(s, b, a), y));
+               } else
+               if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$ge" || cell->type == "$gt") {
+                       bool is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool();
+                       std::vector<int> a = importSigSpec(cell->connections.at("\\A"));
+                       std::vector<int> b = importSigSpec(cell->connections.at("\\B"));
+                       std::vector<int> y = importSigSpec(cell->connections.at("\\Y"));
+                       extendSignalWidth(a, b, cell);
+                       if (cell->type == "$lt")
+                               ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), y.at(0));
+                       if (cell->type == "$le")
+                               ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), y.at(0));
+                       if (cell->type == "$eq")
+                               ez->SET(ez->vec_eq(a, b), y.at(0));
+                       if (cell->type == "$ne")
+                               ez->SET(ez->vec_ne(a, b), y.at(0));
+                       if (cell->type == "$ge")
+                               ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), y.at(0));
+                       if (cell->type == "$gt")
+                               ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), y.at(0));
                } else
                        log_error("Can't handle cell type %s in SAT generator yet.\n", RTLIL::id2cstr(cell->type));
        }
index d6ebd678be2d6e600bc09492ca797c474c7b3a86..cf9dd65b900f180f6e5af45fe5125cdbba3a2098 100644 (file)
@@ -34,6 +34,7 @@ ezSAT::ezSAT()
 
        cnfConsumed = false;
        cnfVariableCount = 0;
+       cnfClausesCount = 0;
 }
 
 ezSAT::~ezSAT()
@@ -331,6 +332,7 @@ void ezSAT::clear()
 {
        cnfConsumed = false;
        cnfVariableCount = 0;
+       cnfClausesCount = 0;
        cnfLiteralVariables.clear();
        cnfExpressionVariables.clear();
        cnfClauses.clear();
@@ -342,11 +344,13 @@ void ezSAT::assume(int id)
        int idx = bind(id);
        cnfClauses.push_back(std::vector<int>(1, idx));
        cnfAssumptions.insert(id);
+       cnfClausesCount++;
 }
 
 void ezSAT::add_clause(const std::vector<int> &args)
 {
        cnfClauses.push_back(args);
+       cnfClausesCount++;
 }
 
 void ezSAT::add_clause(const std::vector<int> &args, bool argsPolarity, int a, int b, int c)
index 29b7aca71b094821513ab27df4114ab1237aef9e..ea873a859601492446fcd09782363c5864186a27 100644 (file)
@@ -55,7 +55,7 @@ private:
        std::vector<std::pair<OpId, std::vector<int>>> expressions;
 
        bool cnfConsumed;
-       int cnfVariableCount;
+       int cnfVariableCount, cnfClausesCount;
        std::vector<int> cnfLiteralVariables, cnfExpressionVariables;
        std::vector<std::vector<int>> cnfClauses;
        std::set<int> cnfAssumptions;
@@ -137,6 +137,7 @@ public:
        int bound(int id) const;
 
        int numCnfVariables() const { return cnfVariableCount; }
+       int numCnfClauses() const { return cnfClausesCount; }
        const std::vector<std::vector<int>> &cnf() const { return cnfClauses; }
 
        void consumeCnf();
index 1655e6972795b0ec23a5073b1f32763114f21392..56d293260b81fa86926e794eddcb075b83d0b512 100644 (file)
@@ -255,7 +255,7 @@ int main()
                ez.assume(ez.ordered(vecvec[0], vecvec[1]));
        
        printf("Found and eliminated %d spatial symmetries.\n", int(symmetries.size()));
-       printf("Generated %d clauses over %d variables.\n", ez.numCnfVariables(), int(ez.cnf().size()));
+       printf("Generated %d clauses over %d variables.\n", ez.numCnfClauses(), ez.numCnfVariables());
 
        std::vector<int> modelExpressions;
        std::vector<bool> modelValues;
index b7798ab2e5309975e1973ab0b70c6f5e40b4f7dc..e2eb174973a43afaed432149c502bba70fc8e2f9 100644 (file)
@@ -1,3 +1,3 @@
 read_verilog example.v
-techmap; opt
+techmap; opt; abc; opt
 sat_solve -show a -set y 1'b1
index 1644eaaa11e3b7c3ca4260a12e7505120e4cd3a9..0f826fc94c5bb538879e358bbf3b480aa3ffaa30 100644 (file)
@@ -129,7 +129,7 @@ struct SatSolvePass : public Pass {
                std::vector<std::pair<std::string, std::string>> sets;
                std::vector<std::string> shows;
 
-               log_header("Executing SAT_SOLVE pass (detecting logic loops).\n");
+               log_header("Executing SAT_SOLVE pass (solving SAT problems in the circuit).\n");
 
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++) {
@@ -189,7 +189,7 @@ struct SatSolvePass : public Pass {
                                satgen.importCell(c.second);
                                import_cell_counter++;
                        }
-               log("Imported %d cells.\n", import_cell_counter);
+               log("Imported %d cells to SAT database.\n", import_cell_counter);
 
                std::vector<int> modelExpressions;
                std::vector<bool> modelValues;
@@ -227,7 +227,7 @@ struct SatSolvePass : public Pass {
                        }
                }
 
-               log("Solving problem with %d variables and %d clauses..\n", ez.numCnfVariables(), int(ez.cnf().size()));
+               log("Solving problem with %d variables and %d clauses..\n", ez.numCnfVariables(), ez.numCnfClauses());
                if (ez.solve(modelExpressions, modelValues))
                {
                        log("SAT solving finished - model found:\n");