glift: Initial implementation of GLIFT model construction.
authorAlberto Gonzalez <boqwxp@airmail.cc>
Tue, 21 Apr 2020 03:21:28 +0000 (03:21 +0000)
committerAlberto Gonzalez <boqwxp@airmail.cc>
Wed, 1 Jul 2020 19:51:45 +0000 (19:51 +0000)
passes/cmds/glift.cc

index 8ef92ddf79ceec08ada3125e5d493e07c0597cd4..58a5ec1c333dda467809d04bec7a9c6165289644 100644 (file)
@@ -25,7 +25,158 @@ USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
 
 struct GliftPass : public Pass {
-       GliftPass() : Pass("glift", "create and transform GLIFT models") { }
+       private:
+
+       bool opt_create, opt_taintconstants;
+       std::vector<std::string> args;
+       std::vector<std::string>::size_type argidx;
+       RTLIL::Module *module;
+
+       void parse_args() {
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-create") {
+                               opt_create = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-taint-constants") {
+                               opt_taintconstants = true;
+                               continue;
+                       }
+                       break;
+               }
+       }
+
+       RTLIL::SigSpec get_corresponding_taint_signal(RTLIL::SigSpec sig) {
+               RTLIL::SigSpec ret;
+
+               //Get the connected wire for the cell port:
+               log_assert(sig.is_wire() || sig.is_fully_const());
+               log_assert(sig.is_wire() || sig.is_fully_const());
+
+               //Get a SigSpec for the corresponding taint signal for the cell port, creating one if necessary:
+               if (sig.is_wire()) {
+                       RTLIL::Wire *w = module->wire(sig.as_wire()->name.str() + "_t");
+                       if (w == nullptr) w = module->addWire(sig.as_wire()->name.str() + "_t", 1);
+                       ret = w;
+               }
+               else if (sig.is_fully_const() && opt_taintconstants)
+                       ret = RTLIL::State::S1;
+               else if (sig.is_fully_const())
+                       ret = RTLIL::State::S0;
+               else
+                       log_cmd_error("Cell port SigSpec has unexpected type.\n");
+
+               //Finally, if the cell port was a module input or output, make sure the corresponding taint signal is marked, too:
+               if(sig.is_wire() && sig.as_wire()->port_input)
+                       ret.as_wire()->port_input = true;
+               if(sig.is_wire() && sig.as_wire()->port_output)
+                       ret.as_wire()->port_output = true;
+
+               return ret;
+       }
+
+       void create_precise_glift_logic() {
+               std::vector<RTLIL::SigSig> connections(module->connections());
+               std::vector<RTLIL::SigSig> new_connections;
+
+               for(auto &cell : module->cells().to_vector()) {
+                       if (!cell->type.in("$_AND_", "$_OR_", "$_NOT_", "$anyconst", "$allconst", "$assume", "$assert")) {
+                               log_cmd_error("Invalid cell type \"%s\" found.  Module must be techmapped.\n", cell->type.c_str());
+                       }
+                       if (cell->type.in("$_AND_", "$_OR_")) {
+                               const unsigned int A = 0, B = 1, Y = 2;
+                               const unsigned int NUM_PORTS = 3;
+                               RTLIL::SigSpec ports[NUM_PORTS] = {cell->getPort(ID::A), cell->getPort(ID::B), cell->getPort(ID::Y)};
+                               RTLIL::SigSpec port_taints[NUM_PORTS];
+
+                               if (ports[A].size() != 1 || ports[B].size() != 1 || ports[Y].size() != 1)
+                                       log_cmd_error("Multi-bit signal found.  Run `splitnets` first.\n");
+                               for (unsigned int i = 0; i < NUM_PORTS; ++i)
+                                       port_taints[i] = get_corresponding_taint_signal(ports[i]);
+
+                               if (cell->type == "$_AND_") {
+                                       //We are basically trying to replace each AND cell with an AN2_SH2 cell:
+                                       //module AN2_SH2(A, A_t, B, B_t, Y, Y_t);
+                                       //  input A, A_t, B, B_t;
+                                       //  output Y, Y_t;
+                                       //
+                                       //  assign Y = A & B;
+                                       //  assign Y_t = A & B_t | B & A_t | A_t & B_t;
+                                       //endmodule
+                                       auto subexpr1 = module->And(cell->name.str() + "_t_1", ports[A], port_taints[B], false, cell->get_src_attribute());
+                                       auto subexpr2 = module->And(cell->name.str() + "_t_2", ports[B], port_taints[A], false, cell->get_src_attribute());
+                                       auto subexpr3 = module->And(cell->name.str() + "_t_3", port_taints[A], port_taints[B], false, cell->get_src_attribute());
+                                       auto subexpr4 = module->Or(cell->name.str() + "_t_4", subexpr1, subexpr2, false, cell->get_src_attribute());
+                                       module->addOr(cell->name.str() + "_t_5", subexpr4, subexpr3, port_taints[Y], false, cell->get_src_attribute());
+                               }
+
+                               else if (cell->type == "$_OR_") {
+                                       //We are basically trying to replace each OR cell with an OR2_SH2 cell:
+                                       //module OR2_SH2(A, A_t, B, B_t, Y, Y_t);
+                                       //  input A, A_t, B, B_t;
+                                       //  output Y, Y_t;
+                                       //
+                                       //  assign Y = A | B;
+                                       //  assign Y_t = ~A & B_t | ~B & A_t | A_t & B_t;
+                                       //endmodule
+                                       RTLIL::SigSpec n_port_a = module->LogicNot(cell->name.str() + "_t_1", ports[A], false, cell->get_src_attribute());
+                                       RTLIL::SigSpec n_port_b = module->LogicNot(cell->name.str() + "_t_2", ports[B], false, cell->get_src_attribute());
+                                       auto subexpr1 = module->And(cell->name.str() + "_t_3", n_port_a, port_taints[B], false, cell->get_src_attribute());
+                                       auto subexpr2 = module->And(cell->name.str() + "_t_4", n_port_b, port_taints[A], false, cell->get_src_attribute());
+                                       auto subexpr3 = module->And(cell->name.str() + "_t_5", port_taints[A], port_taints[B], false, cell->get_src_attribute());
+                                       auto subexpr4 = module->Or(cell->name.str() + "_t_6", subexpr1, subexpr2, false, cell->get_src_attribute());
+                                       module->addOr(cell->name.str() + "_t_7", subexpr4, subexpr3, port_taints[Y], false, cell->get_src_attribute());
+                               }
+
+                               else log_cmd_error("This is a bug (1).\n");
+                       }
+                       else if (cell->type.in("$_NOT_")) {
+                               const unsigned int A = 0, Y = 1;
+                               const unsigned int NUM_PORTS = 2;
+                               RTLIL::SigSpec ports[NUM_PORTS] = {cell->getPort(ID::A), cell->getPort(ID::Y)};
+                               RTLIL::SigSpec port_taints[NUM_PORTS];
+
+                               if (ports[A].size() != 1 || ports[Y].size() != 1)
+                                       log_cmd_error("Multi-bit signal found.  Run `splitnets` first.\n");
+                               for (unsigned int i = 0; i < NUM_PORTS; ++i)
+                                       port_taints[i] = get_corresponding_taint_signal(ports[i]);
+
+                               if (cell->type == "$_NOT_") {
+                                       //We are basically trying to replace each NOT cell with an IV_SH2 cell:
+                                       //module IV_SH2(A, A_t, Y, Y_t);
+                                       //  input A, A_t;
+                                       //  output Y, Y_t;
+                                       //
+                                       //  assign Y = ~A;
+                                       //  assign Y_t = A_t;
+                                       //endmodule
+                                       new_connections.emplace_back(port_taints[Y], port_taints[A]);
+                               }
+                               else log_cmd_error("This is a bug (1).\n");
+                       }
+               } //end foreach cell in cells
+
+               for (auto &conn : connections) {
+                       RTLIL::SigSpec first = get_corresponding_taint_signal(conn.first);
+                       RTLIL::SigSpec second = get_corresponding_taint_signal(conn.second);
+
+                       module->connect(get_corresponding_taint_signal(conn.first), get_corresponding_taint_signal(conn.second));
+
+                       if(conn.second.is_wire() && conn.second.as_wire()->port_input)
+                               second.as_wire()->port_input = true;
+                       if(conn.first.is_wire() && conn.first.as_wire()->port_output)
+                               first.as_wire()->port_output = true;
+               } //end foreach conn in connections
+
+               for (auto &conn : new_connections)
+                       module->connect(conn);
+
+               module->fixup_ports(); //we have some new taint signals in the module interface
+       }
+
+       public:
+
+       GliftPass() : Pass("glift", "create and transform GLIFT models"), opt_create(false), opt_taintconstants(false), module(nullptr) { }
        void help() YS_OVERRIDE
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@@ -41,9 +192,29 @@ struct GliftPass : public Pass {
                log("    Replaces the current or specified module with one that has additional \"taint\"\n");
                log("    inputs, outputs, and internal nets along with precise taint-tracking logic.\n");
                log("\n");
+               log("  -taint-constants");
+               log("    Constant values in the design are labeled as tainted.\n");
+               log("    (default: label constants as un-tainted)\n");
+               log("\n");
        }
-       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+       void execute(std::vector<std::string> _args, RTLIL::Design *design) YS_OVERRIDE
        {
+               log_header(design, "Executing GLIFT pass (creating and manipulating GLIFT models).\n");
+
+               args = _args;
+               parse_args();
+               extra_args(args, argidx, design);
+
+               for (auto mod : design->selected_modules()) {
+                       if (module)
+                               log_cmd_error("Only one module may be selected for the glift pass! Flatten the design if necessary. (selected: %s and %s)\n", log_id(module), log_id(mod));
+                       module = mod;
+               }
+               if (module == nullptr)
+                       log_cmd_error("Can't operate on an empty selection!\n");
+
+               if (opt_create)
+                       create_precise_glift_logic();
        }
 } GliftPass;