| #!/usr/bin/env splrun | |
| var idx = 0; | |
| var count_nand = 0; | |
| var count_nor = 0; | |
| function makeNAND(net, id) | |
| { | |
| count_nand++; | |
| net["${id}_VDD"] = "${id}_pa S"; | |
| net["${id}_VSS"] = "${id}_nb S"; | |
| net["${id}_A"] = "${id}_pa G"; | |
| net["${id}_B"] = "${id}_pb G"; | |
| net["${id}_Y"] = "${id}_pb D"; | |
| return <:> | |
| : node ${id}_pa pmos S 1 D 1 G 1 | |
| : node ${id}_pb pmos S 1 D 1 G 1 | |
| : node ${id}_na nmos S 1 D 1 G 1 | |
| : node ${id}_nb nmos S 1 D 1 G 1 | |
| : connect ${id}_pa S ${id}_pb S | |
| : connect ${id}_pa D ${id}_pb D | |
| : connect ${id}_pa D ${id}_na D | |
| : connect ${id}_na S ${id}_nb D | |
| : connect ${id}_pa G ${id}_na G | |
| : connect ${id}_pb G ${id}_nb G | |
| </>; | |
| } | |
| function makeNOR(net, id) | |
| { | |
| count_nor++; | |
| net["${id}_VDD"] = "${id}_pa S"; | |
| net["${id}_VSS"] = "${id}_nb S"; | |
| net["${id}_A"] = "${id}_pa G"; | |
| net["${id}_B"] = "${id}_pb G"; | |
| net["${id}_Y"] = "${id}_pb D"; | |
| return <:> | |
| : node ${id}_pa pmos S 1 D 1 G 1 | |
| : node ${id}_pb pmos S 1 D 1 G 1 | |
| : node ${id}_na nmos S 1 D 1 G 1 | |
| : node ${id}_nb nmos S 1 D 1 G 1 | |
| : connect ${id}_pa D ${id}_pb S | |
| : connect ${id}_pb D ${id}_na D | |
| : connect ${id}_pb D ${id}_nb D | |
| : connect ${id}_na S ${id}_nb S | |
| : connect ${id}_pa G ${id}_na G | |
| : connect ${id}_pb G ${id}_nb G | |
| </>; | |
| } | |
| function makeGraph(seed, gates, primaryInputs, primaryOutputs) | |
| { | |
| srand(seed); | |
| var code = ""; | |
| var net, vdd, vss, outputs; | |
| var unusedOutpus; | |
| for (var i = 0; i < gates; i++) | |
| { | |
| var id = fmt("G%d", idx++); | |
| if (rand(2) == 0) | |
| code ~= makeNAND(net, id); | |
| else | |
| code ~= makeNOR(net, id); | |
| if (i == 0) { | |
| vdd = net["${id}_VDD"]; | |
| vss = net["${id}_VSS"]; | |
| } else { | |
| code ~= <:> | |
| : connect $vdd ${net["${id}_VDD"]} | |
| : connect $vss ${net["${id}_VSS"]} | |
| </>; | |
| } | |
| var inIdx1 = rand((elementsof outputs) + 1); | |
| if (inIdx1 < elementsof outputs) { | |
| code ~= " connect ${outputs[inIdx1]} ${net["${id}_A"]}\n"; | |
| delete unusedOutpus[outputs[inIdx1]]; | |
| } else | |
| push primaryInputs, net["${id}_A"]; | |
| var inIdx2 = rand((elementsof outputs) + 1); | |
| if (inIdx2 < elementsof outputs) { | |
| code ~= " connect ${outputs[inIdx2]} ${net["${id}_B"]}\n"; | |
| delete unusedOutpus[outputs[inIdx2]]; | |
| } else | |
| push primaryInputs, net["${id}_B"]; | |
| unusedOutpus[net["${id}_Y"]] = 1; | |
| push outputs, net["${id}_Y"]; | |
| } | |
| foreach netDecl (unusedOutpus) | |
| push primaryOutputs, netDecl; | |
| return code; | |
| } | |
| function makeConnections(fromNets, toNets) | |
| { | |
| var code = ""; | |
| foreach[] toNet (toNets) { | |
| var fromNet = fromNets[rand(elementsof fromNets)]; | |
| code != " connect $fromNet $toNet\n"; | |
| } | |
| return code; | |
| } | |
| var numNodes; | |
| write(<:> | |
| : graph nand | |
| <?spl var net = []; ?> | |
| ${makeNAND(net, "nand")} | |
| : extern ${net["nand_VDD"]} | |
| : extern ${net["nand_VSS"]} | |
| : extern ${net["nand_A"]} | |
| : extern ${net["nand_B"]} | |
| : extern ${net["nand_Y"]} | |
| : endgraph | |
| : | |
| : graph nor | |
| ${makeNOR(net, "nor")} | |
| : extern ${net["nor_VDD"]} | |
| : extern ${net["nor_VSS"]} | |
| : extern ${net["nor_A"]} | |
| : extern ${net["nor_B"]} | |
| : extern ${net["nor_Y"]} | |
| : endgraph | |
| : | |
| : graph needle_1 | |
| <?spl var ports; ?> | |
| ${makeGraph(1, 100, ports, ports)} | |
| <?spl numNodes["needle_1"] = idx*4; ?> | |
| <spl:foreach var="[]net" list="ports"> | |
| : extern $net | |
| </spl:foreach> | |
| : endgraph | |
| : | |
| : graph needle_2 | |
| <?spl var ports; ?> | |
| ${makeGraph(2, 200, ports, ports)} | |
| <?spl numNodes["needle_2"] = idx*4; ?> | |
| <spl:foreach var="[]net" list="ports"> | |
| : extern $net | |
| </spl:foreach> | |
| : endgraph | |
| : | |
| : graph needle_3 | |
| <?spl var ports; ?> | |
| ${makeGraph(3, 300, ports, ports)} | |
| <?spl numNodes["needle_3"] = idx*4; ?> | |
| <spl:foreach var="[]net" list="ports"> | |
| : extern $net | |
| </spl:foreach> | |
| : endgraph | |
| : | |
| : graph haystack | |
| <?spl count_nand=0; count_nor=0; ?> | |
| <?spl var inPorts1, outPorts1; ?> | |
| ${makeGraph(1, 100, inPorts1, outPorts1)} | |
| <?spl var inPorts2, outPorts2; ?> | |
| ${makeGraph(2, 200, inPorts2, outPorts2)} | |
| <?spl var inPorts3, outPorts3; ?> | |
| ${makeGraph(3, 300, inPorts3, outPorts3)} | |
| <?spl var inPorts4, outPorts4; ?> | |
| ${makeGraph(2, 200, inPorts4, outPorts4)} | |
| <?spl var inPorts5, outPorts5; ?> | |
| ${makeGraph(1, 100, inPorts5, outPorts5)} | |
| <?spl numNodes["haystack"] = idx*4; ?> | |
| ${makeConnections(outPorts1, inPorts2)} | |
| ${makeConnections(outPorts2, inPorts3)} | |
| ${makeConnections(outPorts3, inPorts4)} | |
| ${makeConnections(outPorts4, inPorts5)} | |
| : endgraph | |
| : | |
| : solve nand haystack false | |
| : expect $count_nand | |
| : clearoverlap | |
| : | |
| : solve nor haystack false | |
| : expect $count_nor | |
| : clearoverlap | |
| : | |
| : solve needle_1 haystack false | |
| : expect 2 | |
| : | |
| : solve needle_2 haystack false | |
| : expect 2 | |
| : | |
| : solve needle_3 haystack false | |
| : expect 1 | |
| </>); | |
| numNodes["haystack"] -= numNodes["needle_3"]; | |
| numNodes["needle_3"] -= numNodes["needle_2"]; | |
| numNodes["needle_2"] -= numNodes["needle_1"]; | |
| write(<:> | |
| : | |
| : # Needle_1: ${numNodes["needle_1"]} transistors | |
| : # Needle_2: ${numNodes["needle_2"]} transistors | |
| : # Needle_3: ${numNodes["needle_3"]} transistors | |
| : # Haystack: ${numNodes["haystack"]} transistors | |
| </>); | |