197 lines
5.5 KiB
C++
197 lines
5.5 KiB
C++
#include "circuit.h"
|
|
|
|
#include <queue>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include "assert.h"
|
|
|
|
void Circuit::init_stems() {
|
|
for(auto& gate: gates) {
|
|
if(gate->outputs.size() >= 2) {
|
|
gate->stem = true;
|
|
}
|
|
gate->stem = true;
|
|
if(gate->stem) {
|
|
stems.push_back(gate);
|
|
}
|
|
}
|
|
|
|
for(Gate *g : gates) {
|
|
if(g->isPI) continue;
|
|
std::queue<Gate*> q;
|
|
std::unordered_map<Gate*, bool> used;
|
|
q.push(g);
|
|
|
|
while(!q.empty()) {
|
|
Gate* now = q.front();
|
|
q.pop();
|
|
for(Gate* in : now->inputs) {
|
|
if(in->stem) {
|
|
g->pre_stems.push_back(in);
|
|
} else if(!used[in]) {
|
|
used[in] = true;
|
|
q.push(in);
|
|
}
|
|
}
|
|
}
|
|
//printf("pre: %s %d\n", g->name.c_str(), g->pre_stems.size());
|
|
}
|
|
|
|
|
|
for(Gate *g : gates) {
|
|
if(g->isPO) continue;
|
|
std::queue<Gate*> q;
|
|
std::unordered_map<Gate*, bool> used;
|
|
q.push(g);
|
|
|
|
while(!q.empty()) {
|
|
Gate* now = q.front();
|
|
q.pop();
|
|
for(Gate* out : now->outputs) {
|
|
if(out->stem) {
|
|
g->suc_stems.push_back(out);
|
|
} else if(!used[out]) {
|
|
used[out] = true;
|
|
q.push(out);
|
|
}
|
|
}
|
|
}
|
|
//printf("pre: %s %d\n", g->name.c_str(), g->pre_stems.size());
|
|
}
|
|
}
|
|
|
|
|
|
void Circuit::init_topo_index() {
|
|
int topo = 1;
|
|
std::queue<Gate*> q;
|
|
|
|
std::unordered_map<Gate*, int> ins;
|
|
for(Gate* gate : gates) {
|
|
ins[gate] = gate->inputs.size();
|
|
}
|
|
|
|
for(auto in : PIs) {
|
|
in->id = topo++;
|
|
q.push(in);
|
|
}
|
|
|
|
while(!q.empty()) {
|
|
Gate* g = q.front(); q.pop();
|
|
for(Gate* out : g->outputs) {
|
|
ins[out]--;
|
|
if(ins[out] == 0) {
|
|
out->id = topo++;
|
|
q.push(out);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Circuit::print_gates() {
|
|
static const char* type2name[9] = {"AND", "NAND", "OR", "NOR", "XOR", "XNOR", "NOT", "BUF", "IN"};
|
|
for(Gate* gate : gates) {
|
|
printf("Gate: %3s (t:%4s v:%d pi:%d po:%d s:%d p:%d s0:%d s1:%d) Inputs:", gate->name.c_str(), type2name[gate->type], gate->value, gate->isPI, gate->isPO, gate->stem, gate->is_propagated(), gate->sa[0], gate->sa[1]);
|
|
for(Gate* in : gate->inputs) {
|
|
printf(" %s", in->name.c_str());
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
bool Circuit::is_valid_circuit() {
|
|
|
|
ll flip_total_weight = 0;
|
|
ll stem_total_weight = 0;
|
|
ll fault_total_weight = 0;
|
|
|
|
int flip_total_cnt = 0;
|
|
int stem_total_cnt = 0;
|
|
int fault_total_cnt = 0;
|
|
|
|
//printf("flip: %d, stem: %d, fault:%d\n", flip_total_weight, stem_total_weight, fault_total_weight);
|
|
|
|
for(Gate* g : gates) {
|
|
|
|
if(flip_need_update[g->id]) {
|
|
flip_total_weight += flip_weight[g->id];
|
|
flip_total_cnt++;
|
|
}
|
|
|
|
if(g->stem && g->cal_value() != g->value) {
|
|
stem_total_weight += stem_weight[g->id];
|
|
}
|
|
|
|
if(g->stem && g->cal_value() == g->value) {
|
|
stem_total_cnt++;
|
|
}
|
|
|
|
if(g->sa[0]) {
|
|
fault_total_weight += fault_weight[g->id][0];
|
|
fault_total_cnt += 1;
|
|
}
|
|
|
|
if(g->sa[1]) {
|
|
fault_total_weight += fault_weight[g->id][1];
|
|
fault_total_cnt += 1;
|
|
}
|
|
|
|
// 检查门的赋值情况
|
|
if(g->cal_value() != g->value) {
|
|
printf("WRONG-ASSGIN: %s \n", g->name.c_str());
|
|
return false;
|
|
}
|
|
|
|
// 检查 PO 的传播设定是否正确
|
|
if(g->isPO) {
|
|
if(g->sa[g->value] != 0 || g->sa[!g->value] == 0 ) {
|
|
printf("WRONG-PO: %s \n", g->name.c_str());
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// 非 PO 情况下检查故障传播是否正确
|
|
|
|
bool sa0 = false;
|
|
bool sa1 = false;
|
|
|
|
for(Gate* out : g->outputs) {
|
|
if(out->cal_value() != out->value) {
|
|
assert(out->stem);
|
|
continue;
|
|
}
|
|
|
|
g->value = !g->value;
|
|
|
|
if(out->cal_value() != out->value) {
|
|
sa0 |= out->is_propagated() && !g->value;
|
|
sa1 |= out->is_propagated() && g->value;
|
|
}
|
|
|
|
g->value = !g->value;
|
|
}
|
|
|
|
if(sa0 != g->sa[0] || sa1 != g->sa[1]) {
|
|
printf("WRONG-SA: %s \n", g->name.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(this->flip_total_weight != flip_total_weight || this->stem_total_weight != stem_total_weight || this->fault_total_weight != fault_total_weight) {
|
|
printf("CIRCUIT CHECK FAILED!\n");
|
|
printf("[wrong] flip: %d, stem: %d, fault:%d\n", this->flip_total_weight, this->stem_total_weight, this->fault_total_weight);
|
|
printf("[right] flip: %d, stem: %d, fault:%d\n", flip_total_weight, stem_total_weight, fault_total_weight);
|
|
return false;
|
|
}
|
|
|
|
if(this->flip_total_cnt != flip_total_cnt || this->stem_total_cnt != stem_total_cnt || this->fault_total_cnt != fault_total_cnt) {
|
|
printf("CIRCUIT CHECK FAILED!\n");
|
|
printf("[wrong] flip_cnt: %d, stem_cnt: %d, fault_cnt:%d\n", this->flip_total_cnt, this->stem_total_cnt, this->fault_total_cnt);
|
|
printf("[right] flip_cnt: %d, stem_cnt: %d, fault_cnt:%d\n", flip_total_cnt, stem_total_cnt, fault_total_weight);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|