A number of issues ...
- There is no current [output] "state" in a gate struct.
- The "operator" functions (e.g.
myand
, myor
, etc.) return a value instead of setting the output value into the struct.
- So, if a gate were connected to multiple outputs, the gate state would be evaluated multiple times (vs once per round).
- The ordering of the gate levels is hardwired into the code (in the
eval
function).
- The operator functions can be greatly simplified using C logic operators.
- We can dynamically determine the order of evaluation of gates by assigning all gates at the same depth to a different list (i.e. separate list for each logic depth)
- For clarity, I added names of the gates and functions to the gate struct.
Here is the refactored code. It is annotated. Unfortunately, I had to rewrite most of it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#define SIZE 10
struct gate;
typedef void (*CallBack)(struct gate *);
typedef struct function {
CallBack f;
char ch[10];
} MyFunction;
typedef struct gate {
const char *sym; // gate name
CallBack f; // operation function
const char *fsym; // name of operation
int depth; // gate's logic depth
struct gate *next; // peer gate at same logic level
int out; // output state/value
struct gate *in1; // input gate
struct gate *in2; // input gate
} Gate;
// list of gates
typedef struct {
Gate *head;
} List;
#define CREATE(_sym,_fnc) \
Gate *_sym = creategate(#_sym,_fnc,#_fnc)
#define MAXDEPTH 100
int bottom_depth; // last/maximum depth
List levels[MAXDEPTH]; // list of gates at a given depth
// leveladd -- add gate to given gate list
void
leveladd(List *list,Gate *add)
{
Gate *prev = NULL;
for (Gate *tmp = list->head; tmp != NULL; tmp = tmp->next)
prev = tmp;
if (prev != NULL)
prev->next = add;
else
list->head = add;
add->next = NULL;
}
// leveldel -- remove gate from given list
void
leveldel(List *list,Gate *del)
{
Gate *prev = NULL;
Gate *cur = list->head;
for (; cur != NULL; cur = cur->next) {
if (cur == del)
break;
prev = cur;
}
if (cur == NULL) {
printf("leveldel: no match -- %s\n",del->sym);
exit(1);
}
if (prev != NULL)
prev->next = del->next;
else
list->head = del->next;
del->next = NULL;
}
// gatevalue -- current output value of gate
int
gatevalue(Gate *gate)
{
return gate->out;
}
void
myand(Gate *gate)
{
int in1 = gatevalue(gate->in1);
int in2 = gatevalue(gate->in2);
gate->out = (in1 & in2) != 0;
}
void
myor(Gate *gate)
{
int in1 = gatevalue(gate->in1);
int in2 = gatevalue(gate->in2);
gate->out = (in1 | in2) != 0;
}
void
mynand(Gate *gate)
{
int in1 = gatevalue(gate->in1);
int in2 = gatevalue(gate->in2);
gate->out = (in1 & in2) != 0;
gate->out = ! gate->out;
}
void
mynor(Gate *gate)
{
int in1 = gatevalue(gate->in1);
int in2 = gatevalue(gate->in2);
gate->out = (in1 | in2) != 0;
gate->out = ! gate->out;
}
void
myxor(Gate *gate)
{
int in1 = gatevalue(gate->in1);
int in2 = gatevalue(gate->in2);
gate->out = (in1 ^ in2) != 0;
}
void
getinput(Gate *cur)
{
int x;
printf("Enter input(0 or 1) for gate '%s': ",cur->sym);
fflush(stdout);
char buf[10];
fgets(buf,sizeof(buf),stdin);
// echo input if coming from redirected file (e.g.) ./myprogram < inp
struct termios tio;
if (tcgetattr(fileno(stdin),&tio) < 0)
fputs(buf,stdout);
x = atoi(buf);
cur->out = x & 1;
}
// creategate -- create a new gate
Gate *
creategate(const char *sym,CallBack f,const char *fsym)
{
Gate *cur;
cur = calloc(1,sizeof(Gate));
// name of this gate
cur->sym = sym;
// save the operator function
cur->f = f;
cur->fsym = fsym;
// assume initial depth
leveladd(&levels[0],cur);
return cur;
}
// redepth -- [recursively] assign new depth to logic gate
void
redepth(Gate *cur,int newdepth)
{
if (cur == NULL)
return;
if (newdepth > cur->depth)
cur->depth = newdepth;
++newdepth;
redepth(cur->in1,newdepth);
redepth(cur->in2,newdepth);
}
// attach -- attach input gates to given gate
void
attach(Gate *a,Gate *b,Gate *c)
{
a->in1 = b;
redepth(b,a->depth + 1);
a->in2 = c;
redepth(c,a->depth + 1);
}
// gatename -- get name of gate
const char *
gatename(Gate *cur)
{
if (cur != NULL)
return cur->sym;
return NULL;
}
// showgate -- show gate and children
void
showgate(Gate *cur)
{
printf(" %s -- %s %s %s (DEPTH: %d)",
cur->sym,gatename(cur->in1),cur->fsym,gatename(cur->in2),cur->depth);
}
// showlevel -- show all gates at given logic level
void
showlevel(List *list)
{
printf("showlevel: %zu\n",list - levels);
for (Gate *cur = list->head; cur != NULL; cur = cur->next) {
showgate(cur);
printf("\n");
}
}
// showall -- show all logic levels
void
showall(const char *who)
{
List *list;
printf("showall: %s\n",who);
for (list = &levels[0]; list < &levels[MAXDEPTH]; ++list) {
if (list->head != NULL)
showlevel(list);
}
}
// moveall -- move gates to their correct logic level lists
void
moveall(void)
{
List *old = &levels[0];
Gate *next;
for (Gate *cur = old->head; cur != NULL; cur = next) {
next = cur->next;
if (cur->depth != 0) {
leveldel(old,cur);
leveladd(&levels[cur->depth],cur);
}
// remember maximum depth
if (cur->depth > bottom_depth)
bottom_depth = cur->depth;
}
}
// eval -- evaluate gate's new value
void
eval(Gate *cur)
{
printf("\n");
printf("eval:");
showgate(cur);
printf("\n");
cur->f(cur);
printf("eval: out=%d\n",cur->out);
}
// doround -- compute values for all gates for single time period
void
doround(void)
{
for (int curdepth = bottom_depth; curdepth >= 0; --curdepth) {
List *list = &levels[curdepth];
for (Gate *cur = list->head; cur != NULL; cur = cur->next)
eval(cur);
}
}
// showround -- compute values for all gates for single time period
void
showround(void)
{
for (int curdepth = bottom_depth; curdepth >= 0; --curdepth) {
List *list = &levels[curdepth];
for (Gate *cur = list->head; cur != NULL; cur = cur->next)
printf("showround: %s --> %d\n",gatename(cur),gatevalue(cur));
}
}
int
main(void)
{
CREATE(a_ptr,mynor);
CREATE(a1_ptr,getinput);
CREATE(a2_ptr,getinput);
attach(a_ptr,a1_ptr,a2_ptr);
CREATE(b_ptr,myand);
CREATE(b1_ptr,getinput);
CREATE(b2_ptr,getinput);
attach(b_ptr,b1_ptr,b2_ptr);
CREATE(c_ptr,myor);
CREATE(c1_ptr,getinput);
CREATE(c2_ptr,getinput);
attach(c_ptr,c1_ptr,c2_ptr);
CREATE(d_ptr,mynand);
attach(d_ptr,a_ptr,b_ptr);
CREATE(e_ptr,myxor);
attach(e_ptr,b_ptr,c_ptr);
CREATE(f_ptr,myor);
attach(f_ptr,d_ptr,e_ptr);
showall("postadd");
showall("premove");
moveall();
showall("postmove");
// we can loop here if we wish
doround();
showround();
return 0;
}
Here is the sample input I used:
1
1
1
1
1
0
Here is the output:
showall: postadd
showlevel: 0
a_ptr -- a1_ptr mynor a2_ptr (DEPTH: 2)
a1_ptr -- (null) getinput (null) (DEPTH: 3)
a2_ptr -- (null) getinput (null) (DEPTH: 3)
b_ptr -- b1_ptr myand b2_ptr (DEPTH: 2)
b1_ptr -- (null) getinput (null) (DEPTH: 3)
b2_ptr -- (null) getinput (null) (DEPTH: 3)
c_ptr -- c1_ptr myor c2_ptr (DEPTH: 2)
c1_ptr -- (null) getinput (null) (DEPTH: 3)
c2_ptr -- (null) getinput (null) (DEPTH: 3)
d_ptr -- a_ptr mynand b_ptr (DEPTH: 1)
e_ptr -- b_ptr myxor c_ptr (DEPTH: 1)
f_ptr -- d_ptr myor e_ptr (DEPTH: 0)
showall: premove
showlevel: 0
a_ptr -- a1_ptr mynor a2_ptr (DEPTH: 2)
a1_ptr -- (null) getinput (null) (DEPTH: 3)
a2_ptr -- (null) getinput (null) (DEPTH: 3)
b_ptr -- b1_ptr myand b2_ptr (DEPTH: 2)
b1_ptr -- (null) getinput (null) (DEPTH: 3)
b2_ptr -- (null) getinput (null) (DEPTH: 3)
c_ptr -- c1_ptr myor c2_ptr (DEPTH: 2)
c1_ptr -- (null) getinput (null) (DEPTH: 3)
c2_ptr -- (null) getinput (null) (DEPTH: 3)
d_ptr -- a_ptr mynand b_ptr (DEPTH: 1)
e_ptr -- b_ptr myxor c_ptr (DEPTH: 1)
f_ptr -- d_ptr myor e_ptr (DEPTH: 0)
showall: postmove
showlevel: 0
f_ptr -- d_ptr myor e_ptr (DEPTH: 0)
showlevel: 1
d_ptr -- a_ptr mynand b_ptr (DEPTH: 1)
e_ptr -- b_ptr myxor c_ptr (DEPTH: 1)
showlevel: 2
a_ptr -- a1_ptr mynor a2_ptr (DEPTH: 2)
b_ptr -- b1_ptr myand b2_ptr (DEPTH: 2)
c_ptr -- c1_ptr myor c2_ptr (DEPTH: 2)
showlevel: 3
a1_ptr -- (null) getinput (null) (DEPTH: 3)
a2_ptr -- (null) getinput (null) (DEPTH: 3)
b1_ptr -- (null) getinput (null) (DEPTH: 3)
b2_ptr -- (null) getinput (null) (DEPTH: 3)
c1_ptr -- (null) getinput (null) (DEPTH: 3)
c2_ptr -- (null) getinput (null) (DEPTH: 3)
eval: a1_ptr -- (null) getinput (null) (DEPTH: 3)
Enter input(0 or 1) for gate 'a1_ptr': 1
eval: out=1
eval: a2_ptr -- (null) getinput (null) (DEPTH: 3)
Enter input(0 or 1) for gate 'a2_ptr': 1
eval: out=1
eval: b1_ptr -- (null) getinput (null) (DEPTH: 3)
Enter input(0 or 1) for gate 'b1_ptr': 1
eval: out=1
eval: b2_ptr -- (null) getinput (null) (DEPTH: 3)
Enter input(0 or 1) for gate 'b2_ptr': 1
eval: out=1
eval: c1_ptr -- (null) getinput (null) (DEPTH: 3)
Enter input(0 or 1) for gate 'c1_ptr': 1
eval: out=1
eval: c2_ptr -- (null) getinput (null) (DEPTH: 3)
Enter input(0 or 1) for gate 'c2_ptr': 0
eval: out=0
eval: a_ptr -- a1_ptr mynor a2_ptr (DEPTH: 2)
eval: out=0
eval: b_ptr -- b1_ptr myand b2_ptr (DEPTH: 2)
eval: out=1
eval: c_ptr -- c1_ptr myor c2_ptr (DEPTH: 2)
eval: out=1
eval: d_ptr -- a_ptr mynand b_ptr (DEPTH: 1)
eval: out=1
eval: e_ptr -- b_ptr myxor c_ptr (DEPTH: 1)
eval: out=0
eval: f_ptr -- d_ptr myor e_ptr (DEPTH: 0)
eval: out=1
showround: a1_ptr --> 1
showround: a2_ptr --> 1
showround: b1_ptr --> 1
showround: b2_ptr --> 1
showround: c1_ptr --> 1
showround: c2_ptr --> 0
showround: a_ptr --> 0
showround: b_ptr --> 1
showround: c_ptr --> 1
showround: d_ptr --> 1
showround: e_ptr --> 0
showround: f_ptr --> 1