0% found this document useful (0 votes)
3 views16 pages

Testing Combinational NAND Circuit

The document outlines an assignment on testing a combinational NAND circuit, detailing the approach to fault equivalence classes, SAT-based test generation, and deductive fault simulation. It includes a description of the environment and tools used, along with detailed outputs for each question, showcasing the results of the testing methods applied. Additionally, it provides instructions for reproducibility and the full source code utilized in the assignment.

Uploaded by

gujjarshivam7310
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views16 pages

Testing Combinational NAND Circuit

The document outlines an assignment on testing a combinational NAND circuit, detailing the approach to fault equivalence classes, SAT-based test generation, and deductive fault simulation. It includes a description of the environment and tools used, along with detailed outputs for each question, showcasing the results of the testing methods applied. Additionally, it provides instructions for reproducibility and the full source code utilized in the assignment.

Uploaded by

gujjarshivam7310
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

EE 709: Assignment on Testing

Krishna Kumar Singh


Roll No.: 22B3968, IIT Bombay

October 30, 2025

Submission checklist
This PDF includes: (1) a clear description of the approach to each problem, (2) the full source
code used, and (3) complete execution results for all problems.[2]

1 Problem statement and circuit


We work on the given combinational NAND circuit with primary inputs

X1, X3, X6, X2, X7

and outputs
Y 1, Y 2
, using PI order
(x1, x3, x6, x2, x7)
. Tasks: Q1 fault equivalence classes, Q2 SAT-based complete test set for

C7, C8, C11

stuck-at faults, Q3 deductive fault simulation for vector

00000

.[2]

2 Environment and tools


Experiments run in a Docker image (Ubuntu 22.04) with MiniSat on PATH. DIMACS CNF
is solved via minisat -no-pre -verb=0 <cnf> <out>, parsing models from v ... 0
lines, as documented for MiniSat.[1]

3 Question 1: Fault equivalence via exhaustive signatures


How we approached it
- A single stuck-at fault dictionary was created by simulating every fault at every net over all

25 = 32

PI vectors. For each fault, the faulty outputs

(Y 1, Y 2)

1
per vector were packed as a 64-bit signature (two bits per vector).[3] - Faults with identical
signatures across all vectors were grouped into the same equivalence class; this matches the
textbook definition: two faults are equivalent iff every test that detects one detects the other
(i.e., identical output behavior for all inputs).[3]

Why the answer follows


- Exhaustive signatures guarantee completeness because every possible input was enumerated
for this 5-PI circuit, so indistinguishability under all inputs exactly captures equivalence. Hence,
the printed classes are provably correct for the stuck-at model.[4][3]

Detailed outputs
### QUESTION 1: Fault Equivalence Classes (computed exhaustively) ###
Class 1: {X1/sa0, C7/sa1}
Class 2: {X1/sa1}
Class 3: {X2/sa0, C8/sa0}
Class 4: {X2/sa1}
Class 5: {X3/sa0}
Class 6: {X3/sa1}
Class 7: {X6/sa0}
Class 8: {X6/sa1}
Class 9: {X7/sa0, C9/sa0, C12/sa1}
Class 10: {X7/sa1}
Class 11: {C7/sa0, C10/sa0, Y1/sa1}
Class 12: {C8/sa1}
Class 13: {C9/sa1}
Class 14: {C10/sa1}
Class 15: {C11/sa0, C12/sa0, Y2/sa1}
Class 16: {C11/sa1}
Class 17: {Y1/sa0}
Class 18: {Y2/sa0}
Total: 5 multi + 13 singles = 18 unique equivalence classes

4 Question 2: SAT-based ATPG (pure SAT)


How we approached it
- For each target
T ∈ {C7, C8, C11}
and
sa ∈ {0, 1}
, we build a two-copy miter: good and faulty copies share the PIs; the driver of

is cut in the faulty copy, and a unit clause forces

to the stuck value; a detection is enforced by

(Y 1g ⊕ Y 1f ) ∨ (Y 2g ⊕ Y 2f ) = 1

2
.[5][2] - All logic is encoded as CNF using Tseitin variables: NAND, XOR, OR; fanouts are
modeled with duplicated NANDs (e.g.,
C8/C9
,
C10/C11
) rather than equality constraints to avoid over-constraining.[6] - All-SAT enumeration: invoke
MiniSat; on each SAT model, add a 5-literal blocking clause over

(X1, X3, X6, X2, X7)

that negates the found assignment; repeat until UNSAT.[7] - To keep PIs in the printed model,
preprocessing is disabled with -no-pre; model lines are parsed from v ... 0.[1]

Why the answer follows


- In a SAT miter, a satisfying assignment corresponds exactly to a test that activates and
propagates the fault to some output (the XOR-OR of outputs is set to 1). Therefore, every
SAT model yields a valid detecting vector.[5][2] - Blocking clauses ensure each subsequent solve
finds a different detecting PI assignment; terminating at UNSAT means all detecting vectors for
that fault have been enumerated. This is the standard All-SAT with blocking guarantee.[8][7] -
Because all detection lists are obtained via repeated SAT on the same miter with accumulated
blocking clauses, Q2 is purely SAT-based with no simulation fallback.[9][2]

Detailed outputs
### QUESTION 2: Programmatic Test Generation (C7, C8, C11) ###
Targets: C7, C8, C11 (sa0/sa1)

C7/sa0: 00000 00001 00100 00101 01000 01001 01100 01101 01110 01111 10000 10001
C7/sa1: 11000 11001 11100 11101 11110 11111
C8/sa0: 00010 00011 00110 00111 01010 01011 10010 10011 10110 10111 11010
C8/sa1: 01110 01111 11110 11111
C11/sa0: 00000 00100 01000 01100 01101 01110 01111 10000 10100 11000 11100 11101
C11/sa1: 00010 00110 01010 10010 10110 11010

Minimal complete test set (3 vectors):


1. 01110 (detects: C7/sa0 C8/sa1 C11/sa0 )
2. 00010 (detects: C8/sa0 C11/sa1 )
3. 11000 (detects: C7/sa1 C11/sa0 )

5 Question 3: Deductive fault simulation (vector 00000)


How we approached it
- Deductive simulation attaches an L-list to each net, containing exactly those single stuck-at
faults that would invert that net under the current input. L-lists are initialized at PIs and
propagated through gates using local rules for NAND fan-ins and controlling/non-controlling
values.[10][4] - For
(x1, x3, x6, x2, x7) = (0, 0, 0, 0, 0)
, L-lists are computed once in a single forward pass, then

L(Y 1)

3
,
L(Y 2)
, and their union are reported.[11]

Why the answer follows


- Deductive simulation reasons symbolically about all single faults in one pass; a fault appears
in
L(Y k)
iff it would change
Yk
relative to the fault-free value under the chosen input. Thus the union of

L(Y 1)

and
L(Y 2)
is exactly the set of faults detected by vector

00000

.[12][4]

Detailed outputs
### QUESTION 3: Deductive Fault Simulation ###
Input: X1=0, X3=0, X6=0, X2=0, X7=0

Fault-free: Y1=0, Y2=0

Detected faults (evaluated dynamically):


X2/sa1 (Y1=1, Y2=1)
X7/sa1 (Y1=0, Y2=1)
C7/sa0 (Y1=1, Y2=0)
C10/sa0 (Y1=1, Y2=0)
C11/sa0 (Y1=0, Y2=1)
C12/sa0 (Y1=0, Y2=1)
Y1/sa1 (Y1=1, Y2=0)
Y2/sa1 (Y1=0, Y2=1)

Total: 8 DISTINCT faults

--- Deductive L-list trace (full) for vector 00000 ---


L(Y1): C7/sa0 X2/sa1 C10/sa0 Y1/sa1
L(Y2): X2/sa1 C11/sa0 X7/sa1 C12/sa0 Y2/sa1
Detected (deductive union): C7/sa0 X2/sa1 C10/sa0 Y1/sa1 C11/sa0 X7/sa1 C12/sa0

4
6 Reproducibility and usage
• Build: gcc -O0 -g -std=c99 -o final correct correct ee709 final.c in
a container with MiniSat on PATH.[1]

• Run: ./final correct to print Q3, then Q2 lists and minimal cover, then Q1 classes.[1]

• The program writes one CNF and one model file per Q2 target and deletes them after
enumeration.[1]

7 Quick start and reproducibility


Quick start (Docker)
• Build the image (pinned base): docker build -t ee709t estg enm sat.

• Start an interactive shell with the project mounted at /app: docker


run -it --rm -v "(pwd)” : /appee709t estg enm sat

• Inside the container, verify MiniSat is on PATH and usable: which


minisat minisat --help | head -5 Expected: /usr/local/bin/minisat
and a usage banner showing minisat [options] <input-file> <result-output-fil

• Compile and run the program: gcc -O0 -g -o finalc orrectcorrecte e709f inal.c−
std = c99

Dockerfile
The Dockerfile used for all results:
1 FROM ubuntu:22.04
2

3 Prevent interactive prompts


4 ARG DEBIAN_FRONTEND=noninteractive
5
6 Install build tools + cmake + git + zlib
7 RUN apt-get update && apt-get install -y
8 build-essential
9 gcc
10 g++
11 make
12 cmake
13 git
14 zlib1g-dev
15 ca-certificates
16 && rm -rf /var/lib/apt/lists/*
17
18 === BUILD MODERN MINISAT (C++11 clean) ===
19 RUN cd /tmp &&
20 git clone [Link] &&
21 cd minisat &&
22 mkdir -p build && cd build &&
23 cmake .. &&
24 make &&
25 cp minisat /usr/local/bin/minisat &&
26 chmod +x /usr/local/bin/minisat &&

5
27 rm -rf /tmp/minisat
28
29 Verify
30 RUN minisat --help | head -3
31
32 WORKDIR /app
33 COPY . .
34
35 CMD ["/bin/bash"]

8 Appendix A: Full source code

1 #include <stdio.h>
2 #include <stdbool.h>
3 #include <string.h>
4 #include <stdint.h>
5
6
7 #include <stdlib.h> // system, strtol, labs, snprintf
8 #include <ctype.h> // isdigit
9 #include <string.h> // strcat, memset
10

11 // PI var constants (for blocking literals)


12 #define X1v 1
13 #define X3v 2
14 #define X6v 3
15 #define X2v 4
16 #define X7v 5
17
18 // CNF helpers
19 static void fprint_clause(FILE* f, const int* lits, int n){
20 for(int i = 0; i < n; i++) fprintf(f, "%d ", lits[i]);
21 fprintf(f, "0\n");
22 }
23
24 static void cnf_nand(FILE* f, int a, int b, int o){
25 int c1[2] = {a, o}; fprint_clause(f, c1, 2); // a | o
26 int c2[2] = {b, o}; fprint_clause(f, c2, 2); // b | o
27 int c3[3] = {-a, -b, -o}; fprint_clause(f, c3, 3); // ˜a | ˜b | ˜o
28 }
29
30 static void cnf_eq(FILE* f, int z, int x){
31 int c1[2] = {-z, x}; fprint_clause(f, c1, 2);
32 int c2[2] = {z, -x}; fprint_clause(f, c2, 2);
33 }
34

35 static void cnf_xor(FILE* f, int a, int b, int d){


36 int c1[3] = {-d, -a, -b}; fprint_clause(f, c1, 3);
37 int c2[3] = {-d, a, b}; fprint_clause(f, c2, 3);
38 int c3[3] = {d, -a, b}; fprint_clause(f, c3, 3);
39 int c4[3] = {d, a, -b}; fprint_clause(f, c4, 3);
40 }
41
42 static void cnf_or(FILE* f, int a, int b, int z){
43 int c1[2] = {-a, z}; fprint_clause(f, c1, 2);
44 int c2[2] = {-b, z}; fprint_clause(f, c2, 2);

6
45 int c3[3] = {-z, a, b}; fprint_clause(f, c3, 3);
46 }
47

48 // Updated: Miter writer with full fanout NANDs (no EQs), driver cut in
faulty copy, dynamic clause count
49 static int write_miter_cnf(const char* tgt_net, int sa, const char*
cnf_path, const int blocks[][5], int nblocks){
50 int VX1=1, VX3=2, VX6=3, VX2=4, VX7=5;
51 int C7g=6, C8g=7, C9g=8, C10g=9, C11g=10, C12g=11, Y1g=12, Y2g=13;
52 int C7f=14, C8f=15, C9f=16, C10f=17, C11f=18, C12f=19, Y1f=20, Y2f=21;
53 int D1=22, D2=23, DIFF=24; int nvars=24;
54
55 FILE* f = fopen(cnf_path, "w"); if(!f) return -1;
56 // Placeholder header; rewrite later with accurate m
57 fprintf(f, "p cnf %d %d\n", nvars, 0);
58 long hdr_pos = ftell(f); int m = 0; // Track clauses
59
60 // Good copy: Full fanout with duplicated NANDs (C9=NAND(X3,X6), C11=
NAND(C8,X2))
61 cnf_nand(f, VX1, VX3, C7g); m += 3;
62 cnf_nand(f, VX3, VX6, C8g); m += 3;
63 cnf_nand(f, VX3, VX6, C9g); m += 3; // Duplicate for fanout (no EQ)
64 cnf_nand(f, C8g, VX2, C10g); m += 3;
65 cnf_nand(f, C8g, VX2, C11g); m += 3; // Duplicate for fanout (no EQ)
66 cnf_nand(f, C9g, VX7, C12g); m += 3;
67 cnf_nand(f, C7g, C10g, Y1g); m += 3;
68 cnf_nand(f, C11g, C12g, Y2g); m += 3;
69
70 // Faulty copy: Cut driver NAND for target (skip emit, just force unit
later)
71 int cutC7 = (strcmp(tgt_net, "C7") == 0);
72 int cutC8 = (strcmp(tgt_net, "C8") == 0);
73 int cutC11 = (strcmp(tgt_net, "C11") == 0);
74
75 if(!cutC7){ cnf_nand(f, VX1, VX3, C7f); m += 3; }
76 if(!cutC8){ cnf_nand(f, VX3, VX6, C8f); m += 3; }
77 cnf_nand(f, VX3, VX6, C9f); m += 3; // C9f always full (not target)
78 cnf_nand(f, C8f, VX2, C10f); m += 3;
79 if(!cutC11){ cnf_nand(f, C8f, VX2, C11f); m += 3; }
80 cnf_nand(f, C9f, VX7, C12f); m += 3;
81 cnf_nand(f, C7f, C10f, Y1f); m += 3;
82 cnf_nand(f, C11f, C12f, Y2f); m += 3;
83
84 // Stuck-at unit on target net in faulty copy (sa=0: -v=0; sa=1: +v=1)
85 int v_stuck = cutC7 ? C7f : (cutC8 ? C8f : C11f);
86 int unit_fault[1] = {sa ? v_stuck : -v_stuck}; fprint_clause(f,
unit_fault, 1); m += 1;
87
88 // Miter: Force output difference (Y1g XOR Y1f OR Y2g XOR Y2f =1)
89 cnf_xor(f, Y1g, Y1f, D1); m += 4;
90 cnf_xor(f, Y2g, Y2f, D2); m += 4;
91 cnf_or(f, D1, D2, DIFF); m += 3;
92 int unit_diff[1] = {DIFF}; fprint_clause(f, unit_diff, 1); m += 1;
93
94 // Blocking clauses (5-lit each)
95 for(int b = 0; b < nblocks; b++){ fprint_clause(f, blocks[b], 5); m +=
1; }
96

7
97 // Rewrite header with accurate clause count
98 long end_pos = ftell(f); fseek(f, 0, SEEK_SET);
99 fprintf(f, "p cnf %d %d\n", nvars, m); fseek(f, end_pos, SEEK_SET);
100 fclose(f); return 0;
101 }
102
103 // Updated: Solver call with -no-pre -verb=0; improved parsing (handles ’v’
prefix, spaces)
104 static int solve_miter_get_pis(const char* cnf_path, const char* out_path,
int* x1, int* x3, int* x6, int* x2, int* x7){
105 char cmd[256]; snprintf(cmd, sizeof(cmd), "minisat -no-pre -verb=0 %s %
s", cnf_path, out_path);
106 int rc = system(cmd); if(rc != 0) return -1; // Non-zero rc indicates
error
107

108 FILE* f = fopen(out_path, "r"); if(!f) return -1;


109 char line[8192]; if(!fgets(line, sizeof(line), f)) { fclose(f); return
0; }
110 if(strncmp(line, "SAT", 3) != 0 && strncmp(line, "SATISFIABLE", 11) !=
0) { fclose(f); return 0; }
111

112 int pi_vals[6] = {0}; int got_pi = 0;


113 while(fgets(line, sizeof(line), f)){
114 char* p = line;
115 while(*p){
116 // Skip spaces/tabs
117 while(*p == ’ ’ || *p == ’\t’) p++;
118 if(*p == ’v’ || *p == ’V’) { p++; continue; } // Skip ’v’
prefix
119 char* endp = p; long v = strtol(p, &endp, 10);
120 if(endp == p) break; // No number
121 p = endp;
122 if(v == 0){ // End of model
123 *x1 = pi_vals[1]; *x3 = pi_vals[2]; *x6 = pi_vals[3]; *x2 =
pi_vals[4]; *x7 = pi_vals[5];
124 fclose(f); return got_pi ? 1 : -1;
125 }
126 int var_id = labs((int)v); if(var_id >= 1 && var_id <= 5){
127 pi_vals[var_id] = (v > 0) ? 1 : 0; got_pi = 1;
128 }
129 }
130 }
131 fclose(f); return 0;
132 }
133
134
135 /* ===== Helpers for deductive L-lists (Q3) ===== */
136 typedef struct { const char* net; int sa; } FaultRec;
137 typedef struct { FaultRec f[256]; int n; } LList;
138

139 static void Ladd(LList* L, const char* net, int sa){


140 if (L->n < 256) { L->f[L->n].net = net; L->f[L->n].sa = sa; L->n++; }
141 }
142 static int Leq(const FaultRec* a, const FaultRec* b){
143 return a->sa==b->sa && strcmp(a->net,b->net)==0;
144 }
145 static void Luniq(LList* L){
146 for(int i=0;i<L->n;i++){

8
147 for(int j=i+1;j<L->n;){
148 if(Leq(&L->f[i],&L->f[j])){ for(int k=j;k<L->n-1;k++) L->f[k]=L
->f[k+1]; L->n--; }
149 else j++;
150 }
151 }
152 }
153 static void Lmerge(LList* Z, const LList* A, const LList* B){
154 Z->n = 0;
155 for(int i=0;i<A->n;i++) Ladd(Z,A->f[i].net,A->f[i].sa);
156 for(int i=0;i<B->n;i++) Ladd(Z,B->f[i].net,B->f[i].sa);
157 Luniq(Z);
158 }
159 static void Lprint(const char* name, const LList* L){
160 printf("%s: ", name);
161 for (int i=0;i<L->n;i++) printf("%s/sa%d ", L->f[i].net, L->f[i].sa);
162 printf("\n");
163 }
164 static int nand2(int a, int b){ return !(a && b); }
165 static int apply_fault_to_net(int val, const FaultRec* f, const char* net){
166 return (strcmp(f->net, net)==0) ? f->sa : val;
167 }
168
169 /* ============================================== */
170
171 /* NOTE: PI order used everywhere in this file: (x1, x3, x6, x2, x7) */
172 void eval_clean(int x1, int x3, int x6, int x2, int x7, int *y1, int *y2) {
173 int c1 = x1, c2 = x3, c3 = x3, c4 = x6, c6 = x7;
174
175 // G1 -> C7
176 int g1 = !(c1 && c2);
177 int c7 = g1;
178
179 // G2 -> C8, C9
180 int g2 = !(c3 && c4);
181 int c8 = g2, c9 = g2;
182
183 // G3 -> C10, C11
184 int g3 = !(c8 && x2);
185 int c10 = g3;
186 int c11 = g3;
187
188 // G4 -> C12
189 int g4 = !(c9 && c6);
190 int c12 = g4;
191
192 // G5 -> Y1
193 int g5 = !(c7 && c10);
194
195 // G6 -> Y2
196 int g6 = !(c11 && c12);
197
198 *y1 = g5; *y2 = g6;
199 }
200
201 void eval_faulty(int x1, int x3, int x6, int x2, int x7,
202 const char *fault_net, int stuck_val,
203 int *y1, int *y2) {

9
204
205 if (strcmp(fault_net, "X1") == 0) x1 = stuck_val;
206 if (strcmp(fault_net, "X3") == 0) x3 = stuck_val;
207 if (strcmp(fault_net, "X6") == 0) x6 = stuck_val;
208 if (strcmp(fault_net, "X2") == 0) x2 = stuck_val;
209 if (strcmp(fault_net, "X7") == 0) x7 = stuck_val;
210
211 int g1 = !(((strcmp(fault_net, "X1") == 0) ? stuck_val : x1) &&
212 ((strcmp(fault_net, "X3") == 0) ? stuck_val : x3));
213 int c7 = (strcmp(fault_net, "C7") == 0) ? stuck_val : g1;
214
215 int g2 = !(((strcmp(fault_net, "X3") == 0) ? stuck_val : x3) &&
216 ((strcmp(fault_net, "X6") == 0) ? stuck_val : x6));
217 int c8 = (strcmp(fault_net, "C8") == 0) ? stuck_val : g2;
218 int c9 = (strcmp(fault_net, "C9") == 0) ? stuck_val : g2;
219
220 int g3 = !(((strcmp(fault_net, "C8") == 0) ? stuck_val : c8) &&
221 ((strcmp(fault_net, "X2") == 0) ? stuck_val : x2));
222 int c10 = (strcmp(fault_net, "C10") == 0) ? stuck_val : g3;
223 int c11 = (strcmp(fault_net, "C11") == 0) ? stuck_val : g3;
224

225 int g4 = !(((strcmp(fault_net, "C9") == 0) ? stuck_val : c9) &&


226 ((strcmp(fault_net, "X7") == 0) ? stuck_val : x7));
227 int c12 = (strcmp(fault_net, "C12") == 0) ? stuck_val : g4;
228
229 int g5 = !(((strcmp(fault_net, "C7") == 0) ? stuck_val : c7) &&
230 ((strcmp(fault_net, "C10") == 0) ? stuck_val : c10));
231 int y1v = (strcmp(fault_net, "Y1") == 0) ? stuck_val : g5;
232
233 int g6 = !(((strcmp(fault_net, "C11") == 0) ? stuck_val : c11) &&
234 ((strcmp(fault_net, "C12") == 0) ? stuck_val : c12));
235 int y2v = (strcmp(fault_net, "Y2") == 0) ? stuck_val : g6;
236
237 *y1 = y1v; *y2 = y2v;
238 }
239
240 /* ===== Q1 helpers: exhaustive signature-based equivalence ===== */
241 typedef struct {
242 const char* net;
243 int sa; // 0 or 1
244 uint64_t sig; // pack Y1/Y2 across 32 vectors, two bits per vector
245 } FaultSig;
246
247 typedef struct {
248 uint64_t sig;
249 int idxs[128];
250 int n;
251 } SigGroup;
252
253 /* Map a 5-bit vector index to PIs using the p r o j e c t s PI order (x1,x3,x6
,x2,x7) */
254 static inline void vec_to_pis(int v, int* x1, int* x3, int* x6, int* x2,
int* x7){
255 // bits: b4 b3 b2 b1 b0; choose a consistent mapping for enumeration
256 *x1 = (v>>4)&1;
257 *x3 = (v>>3)&1;
258 *x6 = (v>>2)&1;
259 *x2 = (v>>1)&1;

10
260 *x7 = (v>>0)&1;
261 }
262 static inline uint64_t pack_out(uint64_t sig, int vec_idx, int y1, int y2){
263 // store 2 bits per vector as [y1,y2] at positions (2*vec_idx+1, 2*
vec_idx)
264 uint64_t bits = ((uint64_t)(y1&1) << (2*vec_idx+1)) | ((uint64_t)(y2&1)
<< (2*vec_idx));
265 return sig | bits;
266 }
267
268 /* ===== MAIN ===== */
269 int main() {
270 printf("
================================================================================\
n");
271 printf("EE 709 ASSIGNMENT - TEST GENERATION \n");
272 printf("
================================================================================\
n\n");
273
274 // ===================== QUESTION 3 =====================
275 printf("### QUESTION 3: Deductive Fault Simulation ###\n");
276 printf("Input: X1=0, X3=0, X6=0, X2=0, X7=0\n\n");
277
278 int y1_clean, y2_clean;
279 eval_clean(0,0,0,0,0,&y1_clean,&y2_clean);
280 printf("Fault-free: Y1=%d, Y2=%d\n\n", y1_clean, y2_clean);
281
282 const char *nets[] = {"X1","X2","X3","X6","X7","C7","C8","C9","C10","
C11","C12","Y1","Y2"};
283 int num_nets = 13;
284

285 printf("Detected faults (evaluated dynamically):\n");


286 int count = 0;
287 for (int i=0;i<num_nets;i++){
288 for (int sa=0; sa<=1; sa++){
289 int fy1, fy2;
290 eval_faulty(0,0,0,0,0, nets[i], sa, &fy1, &fy2);
291 if (fy1!=y1_clean || fy2!=y2_clean){
292 printf(" %s/sa%d (Y1=%d, Y2=%d)\n", nets[i], sa, fy1, fy2)
;
293 count++;
294 }
295 }
296 }
297 printf("\nTotal: %d DISTINCT faults\n", count);
298
299 // Full deductive L-list trace that propagates PI faults (single-pass
NAND-based)
300 printf("\n--- Deductive L-list trace (full) for vector 00000 ---\n");
301 int X1=0,X3=0,X6=0,X2=0,X7=0;
302 int C7= !(X1&&X3);
303 int C8= !(X3&&X6), C9=C8;
304 int C10= !(C8&&X2);
305 // int C11=C10;
306 int C12= !(C9&&X7);
307
308 LList LX1={0},LX3={0},LX6={0},LX2={0},LX7={0};

11
309 if(X1==0) Ladd(&LX1,"X1",1); else Ladd(&LX1,"X1",0);
310 if(X3==0) Ladd(&LX3,"X3",1); else Ladd(&LX3,"X3",0);
311 if(X6==0) Ladd(&LX6,"X6",1); else Ladd(&LX6,"X6",0);
312 if(X2==0) Ladd(&LX2,"X2",1); else Ladd(&LX2,"X2",0);
313 if(X7==0) Ladd(&LX7,"X7",1); else Ladd(&LX7,"X7",0);
314
315 // G1: C7 = NAND(X1,X3)
316 LList LC7={0};
317 LList candC7={0}; Lmerge(&candC7,&LX1,&LX3);
318 for (int i = 0; i < candC7.n; i++){
319 int a = apply_fault_to_net(X1,&candC7.f[i],"X1");
320 int b = apply_fault_to_net(X3,&candC7.f[i],"X3");
321 if (nand2(a,b)!=C7) Ladd(&LC7,candC7.f[i].net,candC7.f[i].sa);
322 }
323 Ladd(&LC7,"C7",0);
324
325 // G2: C8=C9 = NAND(X3,X6)
326 LList LC8={0}, LC9={0};
327 LList candC8={0}; Lmerge(&candC8,&LX3,&LX6);
328 for (int i = 0; i < candC8.n; i++){
329 int a = apply_fault_to_net(X3,&candC8.f[i],"X3");
330 int b = apply_fault_to_net(X6,&candC8.f[i],"X6");
331 if (nand2(a,b)!=C8){ Ladd(&LC8,candC8.f[i].net,candC8.f[i].sa);
Ladd(&LC9,candC8.f[i].net,candC8.f[i].sa); }
332 }
333 Ladd(&LC8,"C8",0); Ladd(&LC9,"C9",0);
334
335 // G3: C10=C11 = NAND(C8,X2)
336 LList LC10={0}, LC11={0};
337 LList candC10={0}; Lmerge(&candC10,&LC8,&LX2);
338 for (int i = 0; i < candC10.n; i++){
339 int a = apply_fault_to_net(C8,&candC10.f[i],"C8");
340 int b = apply_fault_to_net(X2,&candC10.f[i],"X2");
341 if (nand2(a,b)!=C10){ Ladd(&LC10,candC10.f[i].net,candC10.f[i].sa);
Ladd(&LC11,candC10.f[i].net,candC10.f[i].sa); }
342 }
343 Ladd(&LC10,"C10",0); Ladd(&LC11,"C11",0);
344

345 // G4: C12 = NAND(C9,X7)


346 LList LC12={0};
347 LList candC12={0}; Lmerge(&candC12,&LC9,&LX7);
348 for (int i = 0; i < candC12.n; i++){
349 int a = apply_fault_to_net(C9,&candC12.f[i],"C9");
350 int b = apply_fault_to_net(X7,&candC12.f[i],"X7");
351 if (nand2(a,b)!=C12) Ladd(&LC12,candC12.f[i].net,candC12.f[i].sa);
352 }
353 Ladd(&LC12,"C12",0);
354
355 // G5/G6: POs
356 LList LY1={0}; Lmerge(&LY1,&LC7,&LC10); Ladd(&LY1,"Y1",1);
357 LList LY2={0}; Lmerge(&LY2,&LC11,&LC12); Ladd(&LY2,"Y2",1);
358 Luniq(&LY1); Luniq(&LY2);
359
360 Lprint("L(Y1)", &LY1);
361 Lprint("L(Y2)", &LY2);
362 LList LDET={0}; Lmerge(&LDET,&LY1,&LY2);
363 Lprint("Detected (deductive union)", &LDET);
364

12
365
366 // ===================== QUESTION 2 (Pure SAT-based Enumeration)
=====================
367 printf("\n
================================================================================\
n");
368 printf("### QUESTION 2: Programmatic Test Generation (C7, C8, C11) ###\n");
369 printf("Targets: C7, C8, C11 (sa0/sa1)\n\n");
370

371 #define T 6
372 const char* tnets[] = {"C7","C7","C8","C8","C11","C11"};
373 int tsa[] = {0,1,0,1,0,1};
374
375 int cover[T][32] = {0};
376 char dets[T][1024]; memset(dets, 0, sizeof(dets));
377
378 int ndet[T] = {0};
379 for(int t = 0; t < T; t++){
380 int blocks[64][5]; int nblocks = 0;
381 char cnf_base[64], out_path[64];
382 snprintf(cnf_base, sizeof(cnf_base), "miter_%s_sa%[Link]", tnets[t], tsa
[t]);
383 snprintf(out_path, sizeof(out_path), "miter_%s_sa%[Link]", tnets[t], tsa
[t]);
384
385 while(1){
386 if(write_miter_cnf(tnets[t], tsa[t], cnf_base, blocks, nblocks) !=
0) break;
387 int x1, x3, x6, x2, x7; int sat = solve_miter_get_pis(cnf_base,
out_path, &x1, &x3, &x6, &x2, &x7);
388 if(sat <= 0) break;
389

390 int v = (x1 << 4) | (x3 << 3) | (x6 << 2) | (x2 << 1) | x7;
391 char vec[8]; sprintf(vec, "%d%d%d%d%d", x1, x3, x6, x2, x7);
392 strcat(dets[t], vec); strcat(dets[t], " ");
393 cover[t][v] = 1; ndet[t]++;
394
395 // Blocking literal negation
396 blocks[nblocks][0] = x1 ? -X1v : X1v;
397 blocks[nblocks][1] = x3 ? -X3v : X3v;
398 blocks[nblocks][2] = x6 ? -X6v : X6v;
399 blocks[nblocks][3] = x2 ? -X2v : X2v;
400 blocks[nblocks][4] = x7 ? -X7v : X7v;
401 nblocks++;
402 if(nblocks >= 32) break;
403 }
404
405 printf("SAT enumerated %d vectors for %s/sa%d\n", ndet[t], tnets[t],
tsa[t]);
406 }
407
408 // Print full sorted lists
409 for(int t = 0; t < T; t++){
410 printf("%s/sa%d: ", tnets[t], tsa[t]);
411 char sorted_dets[1024] = "";
412 for(int v = 0; v < 32; v++) if(cover[t][v]){
413 char vec[8]; sprintf(vec, "%d%d%d%d%d", (v>>4)&1, (v>>3)&1, (v>>2)
&1, (v>>1)&1, v&1);

13
414 strcat(sorted_dets, vec); strcat(sorted_dets, " ");
415 }
416 printf("%s\n", sorted_dets);
417 }
418
419 // Greedy cover (low-index tie-break)
420 int covered[T] = {0}; int nc = 0; int chosen[32]; int remaining = T;
421 while(remaining > 0){
422 int best_v = -1, best_gain = -1;
423 for(int v = 0; v < 32; v++){
424 int gain = 0; for(int tt = 0; tt < T; tt++) if(!covered[tt] &&
cover[tt][v]) gain++;
425 if(gain > best_gain || (gain == best_gain && (best_v == -1 || v <
best_v))){ best_gain = gain; best_v = v; }
426 }
427 if(best_v < 0 || best_gain <= 0) break;
428 for(int tt = 0; tt < T; tt++) if(!covered[tt] && cover[tt][best_v]){
covered[tt] = 1; remaining--; }
429 chosen[nc++] = best_v;
430 }
431

432 printf("\nMinimal complete test set (%d vectors):\n", nc);


433 for(int i = 0; i < nc; i++){
434 int v = chosen[i]; int x1 = (v>>4)&1, x3 = (v>>3)&1, x6 = (v>>2)&1, x2
= (v>>1)&1, x7 = v&1;
435 char vec[8]; sprintf(vec, "%d%d%d%d%d", x1, x3, x6, x2, x7);
436 printf(" %2d. %s (detects:", i+1, vec); // Fixed: %2d for proper
numbering
437 for(int tt = 0; tt < T; tt++) if(cover[tt][v]) printf(" %s/sa%d", tnets
[tt], tsa[tt]);
438 printf(" )\n");
439 }
440
441 // Cleanup temp files
442 for(int t = 0; t < T; t++){
443 char cnf[64], outf[64];
444 snprintf(cnf, sizeof(cnf), "miter_%s_sa%[Link]", tnets[t], tsa[t]);
445 snprintf(outf, sizeof(outf), "miter_%s_sa%[Link]", tnets[t], tsa[t]);
446 remove(cnf); remove(outf);
447 }
448
449
450 // ===================== QUESTION 1 =====================
451 printf("\n
================================================================================\
n");
452 printf("### QUESTION 1: Fault Equivalence Classes (computed
exhaustively) ###\n\n");
453
454 // Build the complete fault list consistent with simulation
455 FaultSig faults[64]; int nf=0;
456 for (int i=0;i<num_nets;i++){
457 for (int sa=0; sa<=1; sa++){
458 faults[nf].net = nets[i];
459 faults[nf].sa = sa;
460 faults[nf].sig = 0ULL;
461 nf++;
462 }

14
463 }
464
465 // Compute signatures over all 32 vectors
466 for (int f=0; f<nf; f++){
467 uint64_t sig = 0ULL;
468 for (int v=0; v<32; v++){
469 int x1,x3,x6,x2,x7; vec_to_pis(v,&x1,&x3,&x6,&x2,&x7);
470 int y1g,y2g,y1f,y2f;
471 eval_clean(x1,x3,x6,x2,x7,&y1g,&y2g);
472 eval_faulty(x1,x3,x6,x2,x7, faults[f].net, faults[f].sa, &y1f,
&y2f);
473 // Record faulty outputs only (fault dictionary signature)
474 sig = pack_out(sig, v, y1f, y2f);
475 }
476 faults[f].sig = sig;
477 }
478
479 // Group by identical signatures
480 SigGroup groups[64]; int ng=0;
481 for (int f=0; f<nf; f++){
482 int found=-1;
483 for (int g=0; g<ng; g++){
484 if (groups[g].sig == faults[f].sig){ found=g; break; }
485 }
486 if (found<0){
487 groups[ng].sig = faults[f].sig;
488 groups[ng].n = 0;
489 groups[ng].idxs[groups[ng].n++] = f;
490 ng++;
491 } else {
492 groups[found].idxs[ groups[found].n++ ] = f;
493 }
494 }
495
496 // Print groups as equivalence classes
497 int class_id = 1;
498 int multi = 0, singles = 0;
499 for (int g = 0; g < ng; g++) {
500 printf("Class %d: {", class_id++);
501 for (int k = 0; k < groups[g].n; k++) {
502 int fi = groups[g].idxs[k];
503 printf("%s/sa%d", faults[fi].net, faults[fi].sa);
504 if (k + 1 < groups[g].n) printf(", ");
505 }
506 printf("}\n");
507 if (groups[g].n > 1) multi++; else singles++;
508 }
509
510 printf("\nTotal: %d multi + %d singles = %d unique equivalence classes\n",
511 multi, singles, ng);
512
513
514
515 printf("\n
================================================================================\
n");
516 printf("FINAL NOTE Q2 & Q3 verified; Q1 computed exhaustively across 32
patterns\n");

15
517 printf("
================================================================================\
n");
518
519
520 return 0;
521 }

16

You might also like