gb_gates.w
来自「模拟器提供了一个简单易用的平台」· W 代码 · 共 1,677 行 · 第 1/5 页
W
1,677 行
/* set $l=\null$memory address */ if (trace_regs) @<Print register contents@>; if (l>=size) break; /* stop if memory check occurs */ for (v=g->vertices+1,m=rom[l];v<=g->vertices+16;v++,m>>=1) v->val=m&1; /* store bits of memory word in the input gates */ gate_eval(g,NULL,NULL); /* do another RISC cycle */ } if (trace_regs) @<Print a footline@>; @<Dump the register contents into |risc_state|@>; return 0;}@ If tracing is requested, we write on the standard output file.@<Print a headline@>={ for (r=0;r<trace_regs;r++) printf(" r%-2ld ",r); /* register names */ printf(" P XSNKV MEM\n"); /* |prog|, |extra|, status bits, memory */}@ @<Print a footline@>=printf("Execution terminated with memory address %04lx.\n",l);@ Here we peek inside the circuit to see what values are about tobe latched.@<Print register contents@>={ for (r=0;r<trace_regs;r++) { v=g->vertices+(16*r+47); /* most significant bit of register |r| */ m=0; if (v->typ=='L') for (k=0,m=0;k<16;k++,v--) m=2*m+v->alt->val; printf("%04lx ",m); } for (k=0,m=0,v=g->vertices+26;k<10;k++,v--) m=2*m+v->alt->val; /* |prog| */ x=(g->vertices+31)->alt->val; /* |extra| */ s=(g->vertices+27)->alt->val; /* |sign| */ n=(g->vertices+28)->alt->val; /* |nonzero| */ c=(g->vertices+29)->alt->val; /* |carry| */ o=(g->vertices+30)->alt->val; /* |overflow| */ printf("%03lx%c%c%c%c%c ",m<<2, x?'X':'.', s?'S':'.', n?'N':'.', c?'K':'.', o?'V':'.'); if (l>=size) printf("????\n"); else printf("%04lx\n",rom[l]);}@ @<Dump...@>=for (r=0;r<16;r++) { v=g->vertices+(16*r+47); /* most significant bit of register |r| */ m=0; if (v->typ=='L') for (k=0,m=0;k<16;k++,v--) m=2*m+v->alt->val; risc_state[r]=m;}for (k=0,m=0,v=g->vertices+26;k<10;k++,v--) m=2*m+v->alt->val; /* |prog| */m=4*m+(g->vertices+31)->alt->val; /* |extra| */m=2*m+(g->vertices+27)->alt->val; /* |sign| */m=2*m+(g->vertices+28)->alt->val; /* |nonzero| */m=2*m+(g->vertices+29)->alt->val; /* |carry| */m=2*m+(g->vertices+30)->alt->val; /* |overflow| */risc_state[16]=m; /* program register and status bits go here */risc_state[17]=l; /* this is the out-of-range address that caused termination */@ @<Global variables@>=unsigned long risc_state[18];@*Generalized gate graphs. For intermediate computations, it isconvenient to allow two additional types of gates:{\advance\parindent 2em\smallskip\item{|'C'|} denotes a constant gate of value |z.I|.\smallskip\item{|'='|} denotes a copy of a previous gate; utility field |alt|points to that previous gate.\smallskip}\noindentSuch gates might appear anywhere in the graph, possibly interspersed withthe inputs and latches.Here is a simple subroutine that prints a symbolic representation ofa generalized gate graph on the standard output file:@d bit z.I /* field containing the constant value of a |'C'| gate */@d print_gates p_gates /* abbreviation makes chopped-off name unique */@<The |print_gates| routine@>=static void pr_gate(v) Vertex *v;{@+register Arc *a; printf("%s = ",v->name); switch(v->typ) { case 'I':printf("input");@+break; case 'L':printf("latch"); if (v->alt) printf("ed %s",v->alt->name); break; case '~':printf("~ ");@+break; case 'C':printf("constant %ld",v->bit); break; case '=':printf("copy of %s",v->alt->name); } for (a=v->arcs;a;a=a->next) { if (a!=v->arcs) printf(" %c ",(char)v->typ); printf(a->tip->name); } printf("\n");}@#void print_gates(g) Graph *g;{@+register Vertex *v; register Arc *a; for (v=g->vertices;v<g->vertices+g->n;v++) pr_gate(v); for (a=g->outs;a;a=a->next) if (is_boolean(a->tip)) printf("Output %ld\n",the_boolean(a->tip)); else printf("Output %s\n",a->tip->name);}@ @(gb_gates.h@>=#define bit @t\quad@> z.I@ The |reduce| routine takes a generalized graph |g| and uses the identities$\overline{\overline x}=x$ and$$\openup1\jot\vbox{\halign{\hfil$x#0=\null$&$#$,\hfil\quad &\hfil$x#1=\null$&$#$,\hfil\quad &\hfil$x#x=\null$&$#$,\hfil\quad &\hfil$x#\overline x=\null$&$#$,\hfil\cr\land&0&\land&x&\land&x&\land&0\cr\lor&x&\lor&1&\lor&x&\lor&1\cr\oplus&x&\oplus&\overline x&\oplus&0&\oplus&1\cr}}$$to create an equivalent graph having no|'C'| or |'='| or obviously redundant gates. The reduced graph also excludesany gates that are not used directly or indirectly in the computation ofthe output values.@<Internal...@>=static Graph* reduce(g) Graph *g;{@+register Vertex *u, *v; /* the current vertices of interest */ register Arc *a, *b; /* the current arcs of interest */ Arc *aa, *bb; /* their predecessors */ Vertex *latch_ptr; /* top of the latch list */ long n=0; /* the number of marked gates */ Graph *new_graph; /* the reduced gate graph */ Vertex *next_vert=NULL, *max_next_vert=NULL; /* allocation of new vertices */ Arc *avail_arc=NULL; /* list of recycled arcs */ Vertex *sentinel; /* end of the vertices */ if (g==NULL) panic(missing_operand); /* where is |g|? */ sentinel=g->vertices+g->n; while (1) { latch_ptr=NULL; for (v=g->vertices;v<sentinel;v++) @<Reduce gate |v|, if possible, or put it on the latch list@>; @<Check to see if any latch has become constant; if not, |break|@>; } @<Mark all gates that are used in some output@>; @<Copy all marked gates to a new graph@>; gb_recycle(g); return new_graph;}@ We will link latches together via their |v.V| fields.@<Check to see if any latch has become constant; if not, |break|@>={@+char no_constants_yet=1; for (v=latch_ptr;v;v=v->v.V) { u=v->alt; /* the gate whose value will be latched */ if (u->typ=='=') v->alt=u->alt; else if (u->typ=='C') { v->typ='C';@+v->bit=u->bit;@+no_constants_yet=0; } } if (no_constants_yet) break;}@ @d foo x.V /* link field used to find all the gates later */@<Reduce gate |v|, if possible, or put it on the latch list@>={ switch(v->typ) { case 'L': v->v.V=latch_ptr;@+latch_ptr=v;@+break; case 'I': case 'C': break; case '=': u=v->alt; if (u->typ=='=') v->alt=u->alt; else if (u->typ=='C') { v->bit=u->bit;@+goto make_v_constant; } break; case NOT:@<Try to reduce an inverter, then |goto done|@>; case AND:@<Try to reduce an {\sc AND} gate@>;@+goto test_single_arg; case OR:@<Try to reduce an {\sc OR} gate@>;@+goto test_single_arg; case XOR:@<Try to reduce an {\sc EXCLUSIVE-OR} gate@>; test_single_arg: if (v->arcs->next) break; v->alt=v->arcs->tip; make_v_eq: v->typ='=';@+goto make_v_arcless; make_v_1: v->bit=1;@+goto make_v_constant; make_v_0: v->bit=0; make_v_constant: v->typ='C'; make_v_arcless: v->arcs=NULL; }v->bar=NULL; /* this field will point to the complement, if computed later */done: v->foo=v+1; /* this field will link all the vertices together */}@ @<Try to reduce an inverter...@>=u=v->arcs->tip;if (u->typ=='=') u=v->arcs->tip=u->alt;if (u->typ=='C') { v->bit=1-u->bit;@+goto make_v_constant;}@+else if (u->bar) { /* this inverse already computed */ v->alt=u->bar;@+goto make_v_eq;}@+else { u->bar=v;@+v->bar=u;@+goto done;}@ @<Try to reduce an {\sc AND} gate@>=for (a=v->arcs,aa=NULL;a;a=a->next) { u=a->tip; if (u->typ=='=') u=a->tip=u->alt; if (u->typ=='C') { if (u->bit==0) goto make_v_0; goto bypass_and; }@+else@+for (b=v->arcs;b!=a;b=b->next) { if (b->tip==u) goto bypass_and; if (b->tip==u->bar) goto make_v_0; } aa=a;@+continue;bypass_and: if (aa) aa->next=a->next; else v->arcs=a->next;}if (v->arcs==NULL) goto make_v_1;@ @<Try to reduce an {\sc OR} gate@>=for (a=v->arcs,aa=NULL;a;a=a->next) { u=a->tip; if (u->typ=='=') u=a->tip=u->alt; if (u->typ=='C') { if (u->bit) goto make_v_1; goto bypass_or; }@+else@+for (b=v->arcs;b!=a;b=b->next) { if (b->tip==u) goto bypass_or; if (b->tip==u->bar) goto make_v_1; } aa=a;@+continue;bypass_or: if (aa) aa->next=a->next; else v->arcs=a->next;}if (v->arcs==NULL) goto make_v_0;@ @<Try to reduce an {\sc EXCLUSIVE-OR} gate@>={@+long cmp=0; for (a=v->arcs,aa=NULL;a;a=a->next) { u=a->tip; if (u->typ=='=') u=a->tip=u->alt; if (u->typ=='C') { if (u->bit) cmp=1-cmp; goto bypass_xor; }@+else@+for (bb=NULL,b=v->arcs;b!=a;b=b->next) { if (b->tip==u) goto double_bypass; if (b->tip==u->bar) { cmp=1-cmp; goto double_bypass; } bb=b;@+ continue; double_bypass: if (bb) bb->next=b->next; else v->arcs=b->next; goto bypass_xor; } aa=a;@+ continue; bypass_xor: if (aa) aa->next=a->next; else v->arcs=a->next; a->a.A=avail_arc; avail_arc=a; } if (v->arcs==NULL) { v->bit=cmp; goto make_v_constant; } if (cmp) @<Complement one argument of |v|@>;}@ @<Complement one argument of |v|@>={ for (a=v->arcs;;a=a->next) { u=a->tip; if (u->bar) break; /* good, the complement is already known */ if (a->next==NULL) { /* oops, this is our last chance */ @<Create a new vertex for complement of |u|@>; break; } } a->tip=u->bar;}@ Here we've come to a subtle point: If a lot of |XOR| gates involvean input that is set to the constant value~1, the ``reduced'' graphmight actually be larger than the original, in the sense of havingmore vertices (although fewer arcs). Therefore we must have theability to allocate new vertices during the reduction phase of|reduce|. At least one arc has been added to the |avail_arc| listwhenever we reach this portion of the program.@<Create a new vertex for complement of |u|@>=if (next_vert==max_next_vert) { next_vert=gb_typed_alloc(7,Vertex,g->aux_data); if (next_vert==NULL) { gb_recycle(g); panic(no_room+1); /* can't get auxiliary storage! */ } max_next_vert=next_vert+7;}next_vert->typ=NOT;sprintf(name_buf,"%s~",u->name);next_vert->name=gb_save_string(name_buf);next_vert->arcs=avail_arc; /* this is known to be non-|NULL| */avail_arc->tip=u;avail_arc=avail_arc->a.A;next_vert->arcs->next=NULL;next_vert->bar=u;next_vert->foo=u->foo;u->foo=u->bar=next_vert++;@ During the marking phase, we will use the |w.V| field to link thelist of nodes-to-be-marked. That field will turn out to be non-|NULL|only in the marked nodes. (We no longer use its former meaning relatedto complementation, so we call it |lnk| instead of |bar|.)@d lnk w.V /* stack link for marking */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?