📄 gb_gates.w
字号:
% This file is part of the Stanford GraphBase (c) Stanford University 1993@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!@i gb_types.w\def\title{GB\_\,GATES}\prerequisite{GB\_\,GRAPH}@* Introduction. This GraphBase module provides six external subroutines:$$\vbox{\hsize=.8\hsize \everypar{\hangindent3em}\noindent|risc|, a routine that creates a directed acyclic graph based on the logic of a simple RISC computer;\par\noindent|prod|, a routine that creates a directed acyclic graph based on the logic of parallel multiplication circuits;\par\noindent|print_gates|, a routine that outputs a symbolic representation of such directed acyclic graphs;\par\noindent|gate_eval|, a routine that evaluates such directed acyclic graphs by assigning boolean values to each gate;\par\noindent|partial_gates|, a routine that extracts a subgraph by assigning random values to some of the input gates;\par\noindent|run_risc|, a routine that can be used to play with the output of |risc|.}$$Examples of the use of these routines can be found in the demo programs{\sc TAKE\_\,RISC} and {\sc MULTIPLY}.@(gb_gates.h@>=#define print_gates p_gates /* abbreviation for Procrustean linkers */extern Graph *risc(); /* make a network for a microprocessor */extern Graph *prod(); /* make a network for high-speed multiplication */extern void print_gates(); /* write a network to standard output file */extern long gate_eval(); /* evaluate a network */extern Graph *partial_gates(); /* reduce network size */extern long run_risc(); /* simulate the microprocessor */extern unsigned long risc_state[]; /* the output of |run_risc| */@ The directed acyclic graphs produced by {\sc GB\_\,GATES} are GraphBasegraphs with special conventions related to logical networks. Each vertexrepresents a gate of a network, and utility field |val| is a booleanvalue associated with that gate. Utility field |typ| is an ASCII codethat tells what kind of gate is present:{\advance\parindent 2em\smallskip\item{|'I'|} denotes an input gate, whose value is specified externally.\smallskip\item{|'&'|} denotes an \.{AND} gate, whose value is the logical {\sc AND} oftwo or more previous gates (namely, 1 if all those gates are~1, otherwise~0).\smallskip\item{|'|'|} denotes an \.{OR} gate, whose value is the logical {\sc OR} oftwo or more previous gates (namely, 0 if all those gates are~0, otherwise~1).\smallskip\item{|'^'|} denotes an \.{XOR} gate, whose value is the logical {\scEXCLUSIVE-OR} of two or more previous gates (namely, their sum modulo~2).\smallskip\item{|'~'|} denotes an inverter, whose value is the logical complement ofthe value of a single previous gate.\smallskip\item{|'L'|} denotes a latch, whose value depends on past history; it isthe value that was assigned to a subsequent gate when the network was mostrecently evaluated. Utility field |alt| points to that subsequent gate.\smallskip}\noindentLatches can be used to include ``state'' information in a circuit; for example,they correspond to registers of the RISC machine constructed by |risc|.The |prod| procedure does not use latches.The vertices of the directed acyclic graph appear in a special ``topological''order convenient for evaluation: All the input gates come first, followedby all the latches; then come the other types of gates, whose values arecomputed from their predecessors. The arcs of the graph run from each gateto its arguments, and all arguments to a gate precede that gate.If |g| points to such a graph of gates, the utility field |g->outs| points toa list of |Arc| records, denoting ``outputs'' that might be used incertain applications. For example, the outputs of the graphscreated by |prod| correspond to the bits of the product of the numbersrepresented in the input gates.A special convention is used so that the routines will support partialevaluation: The |tip| fields in the output list either point to avertex or hold one of the constant values 0 or~1 when regarded as anunsigned long integer.@d val x.I /* the field containing a boolean value */@d typ y.I /* the field containing the gate type */@d alt z.V /* the field pointing to another related gate */@d outs zz.A /* the field pointing to the list of output gates */@d is_boolean(v) ((unsigned long)(v)<=1) /* is a |tip| field constant? */@d the_boolean(v) ((long)(v)) /* if so, this is its value */@d tip_value(v) (is_boolean(v)? the_boolean(v): (v)->val)@d AND '&'@d OR '|'@d NOT '~'@d XOR '^'@(gb_gates.h@>=#define val @t\quad@> x.I /* the definitions are repeated in the header file */#define typ @t\quad@> y.I#define alt @t\quad@> z.V#define outs @t\quad@> zz.A#define is_boolean(v) @t\quad@> ((unsigned long)(v)<=1)#define the_boolean(v) @t\quad@> ((long)(v))#define tip_value(v) @t\quad@> (is_boolean(v)? the_boolean(v): (v)->val)#define AND @t\quad@> '&'#define OR @t\quad@> '|'#define NOT @t\quad@> '~'#define XOR @t\quad@> '^'@ Let's begin with the |gate_eval| procedure, because it is quite simpleand because it illustrates the conventions just explained. Given a gategraph |g| and optional pointers |in_vec| and |out_vec|, the procedure|gate_eval| will assign values to each gate of~|g|. If |in_vec| isnon-null, it should point to a string of characters, each |'0'| or~|'1'|,that will be assigned to the first gates of the network, in order;otherwise |gate_eval| assumes that all input gates have already receivedappropriate values and it will not change them. New values are computed foreach gate after the bits of |in_vec| have been consumed.If |out_vec| is non-null, it should point to a memory area capable ofreceiving |m+1| characters, where |m| is the number of outputs of~|g|;a string containing the respective output values will be deposited there.If |gate_eval| encounters an unknown gate type, it terminates executionprematurely and returns the value |-1|. Otherwise it returns~0.@<The |gate_eval| routine@>=long gate_eval(g,in_vec,out_vec) Graph *g; /* graph with gates as vertices */ char *in_vec; /* string for input values, or |NULL| */ char *out_vec; /* string for output values, or |NULL| */{@+register Vertex *v; /* the current vertex of interest */ register Arc *a; /* the current arc of interest */ register char t; /* boolean value being computed */ if (!g) return -2; /* no graph supplied! */ v=g->vertices; if (in_vec) @<Read a sequence of input values from |in_vec|@>; for (; v<g->vertices+g->n; v++) { switch (v->typ) { /* branch on type of gate */ case 'I': continue; /* this input gate's value should be externally set */ case 'L': t=v->alt->val;@+break; @t\4\4@>@<Compute the value |t| of a classical logic gate@>; default: return -1; /* unknown gate type! */ } v->val=t; /* assign the computed value */ } if (out_vec) @<Store the sequence of output values in |out_vec|@>; return 0;}@ @<Read a sequence...@>=while (*in_vec && v<g->vertices+g->n) (v++)->val = *in_vec++ - '0';@ @<Store the sequence of output values in |out_vec|@>={ for (a=g->outs; a; a=a->next) *out_vec++='0'+tip_value(a->tip); *out_vec=0; /* terminate the string */}@ @<Compute the value |t| of a classical logic gate@>=case AND: t=1; for (a=v->arcs; a; a=a->next) t &= a->tip->val; break;case OR: t=0; for (a=v->arcs; a; a=a->next) t |= a->tip->val; break;case XOR: t=0; for (a=v->arcs; a; a=a->next) t ^= a->tip->val; break;case NOT: t=1-v->arcs->tip->val; break;@ Here now is an outline of the entire {\sc GB\_\,GATES} module, as seen bythe \CEE/ compiler:@p#include "gb_flip.h" /* we will use the {\sc GB\_\,FLIP} routines for random numbers */#include "gb_graph.h" /* and we will use the {\sc GB\_\,GRAPH} data structures */@h@#@<Private variables@>@;@<Global variables@>@;@<Internal subroutines@>@;@<The |gate_eval| routine@>@;@<The |print_gates| routine@>@;@<The |risc| routine@>@;@<The |run_risc| routine@>@;@<The |prod| routine@>@;@<The |partial_gates| routine@>@;@* The RISC netlist. The subroutine call |risc(regs)| creates agate graph having |regs| registers; the value of |regs| must bebetween 2 and~16, inclusive, otherwise |regs| is set to~16.This gate graph describes the circuitry for a small RISC computer, definedbelow. The total number of gates turns out to be |1400+115*regs|;thus it lies between 1630 (when |regs=2|) and 3240 (when |regs=16|).{\sc EXCLUSIVE-OR} gates are not used; the effect of xoring is obtained whereneeded by means of {\sc AND}s, {\sc OR}s, and inverters.If |risc| cannot do its thing, it returns |NULL| (\.{NULL}) and sets |panic_code|to indicate the problem. Otherwise |risc| returns a pointer to the graph.@d panic(c) @+{@+panic_code=c;@+gb_trouble_code=0;@+return NULL;@+}@<The |risc| routine@>=Graph *risc(regs) unsigned long regs; /* number of registers supported */{@+@<Local variables for |risc|@>@; @# @<Initialize |new_graph| to an empty graph of the appropriate size@>; @<Add the RISC data to |new_graph|@>; if (gb_trouble_code) { gb_recycle(new_graph); panic(alloc_fault); /* oops, we ran out of memory somewhere back there */ } return new_graph;}@ @<Local variables for |risc|@>=Graph *new_graph; /* the graph constructed by |risc| */register long k,r; /* all-purpose indices */@ This RISC machine works with 16-bit registers and 16-bit data words.It cannot write into memory, but it assumes the existence of anexternal read-only memory. The circuit has 16 outputs, representingthe 16 bits of a memory address register. It also has 17 inputs, thelast 16 of which are supposed to be set to the contents of the memoryaddress computed on the previous cycle. Thus we can run the machineby accessing memory between calls of |gate_eval|. The first inputbit, called \.{RUN}, is normally set to~1; if it is~0, the otherinputs are effectively ignored and all registers and outputs will becleared to~0. Input bits for the memory appear in ``little-endianorder,'' that is, least significant bit first; but the output bits forthe memory address register appear in ``big-endian order,'' mostsignificant bit first.Words read from memory are interpreted as instructions having the followingformat:$$\vbox{\offinterlineskip \def\\#1&{\omit&} \hrule \halign{&\vrule#&\strut\sevenrm\hbox to 1.7em{\hfil#\hfil}\cr height 5pt&\multispan7\hfill&&\multispan7\hfill&&\multispan3\hfill &&\multispan3\hfill&&\multispan7\hfill&\cr &\multispan7\hfill\.{DST}\hfill&&\multispan7\hfill\.{MOD}\hfill &&\multispan3\hfill\.{OP}\hfill&&\multispan3\hfill\.{A}\hfill &&\multispan7\hfill\.{SRC}\hfill&\cr height 5pt&\multispan7\hfill&&\multispan7\hfill&&\multispan3\hfill &&\multispan3\hfill&&\multispan7\hfill&\cr \noalign{\hrule} \\15&\\14&\\13&\\12&\\11&\\10&\\9&\\8&\\7&\\6&\\5&\\4&\\3&\\2&\\1&% \\0&\omit\cr}}$$The \.{SRC} and \.A fields specify a ``source'' value.If $\.A=0$, the source is \.{SRC}, treated as a 16-bit signednumber between $-8$ and $+7$ inclusive.If $\.A=1$, the source is the contents of register \.{DST} plus the(signed) value of \.{SRC}. If $\.A=2$, the source is the contents of register\.{SRC}. And if $\.A=3$, the source is the contents of the memory locationwhose address is the contents of register \.{SRC}. Thus, for example,if $\.{DST}=3$ and $\.{SRC}=10$, and if \.{r3} contains 17 while \.{r10}contains 1009, the source value will be $-6$ if $\.A=0$,or $17-6=11$ if $\.A=1$, or 1009 if $\.A=2$, or the contents of memory location1009 if $\.A=3$.The \.{DST} field specifies the number of the destination register. Thisregister receives a new value based on its previous value and the sourcevalue, as prescribed by the operation defined in the \.{OP} and \.{MOD}fields. For example, when $\.{OP}=0$, a general logical operation isperformed, as follows:Suppose the bits of \.{MOD} are called $\mu_{11}\mu_{10}\mu_{01}\mu_{00}$ from left to right. Then if the $k$th bit of the destination registercurrently is equal to~$i$ and the $k$th bit of the source value isequal to~$j$, the general logical operator changes the $k$th bit ofthe destination register to~$\mu_{ij}$. If the \.{MOD} bits are,for example, $1010$, the source value is simply copied to thedestination register; if $\.{MOD}=0110$, an exclusive-or is done;if $\.{MOD}=0011$, the destination register is complemented and thesource value is effectively ignored.The machine contains four status bits called \.S (sign), \.N (nonzero),\.K (carry), and \.V (overflow). Every general logical operation sets\.S equal to the sign of the new result transferred to the destinationregister; this is bit~15, the most significant bit. A general logicaloperation also sets \.N to~1 if any of the other 15 bits are~1, to~0if all of the other bits are~0. Thus \.S and \.N both become zero if andonly if the new result is entirely zero. Logical operations do not changethe values of \.K and~\.V; the latter are affected only by the arithmeticoperations described below.The status of the \.S and \.N bits can be tested by using theconditional load operator, $\.{OP}=2$: This operation loads the sourcevalue into the destination register if and only if \.{MOD} bit$\mu_{ij}=1$, where $i$ and~$j$ are the current values of \.S and~\.N,respectively. For example, if $\.{MOD}=0011$, the source value isloaded if and only if $\.S=0$, which means that the last valueaffecting \.S and~\.N was greater than or equal to zero. If$\.{MOD}=1111$, loading is always done; this option provides a wayto move source to destination without affecting \.S or~\.N.A second conditional load operator, $\.{OP}=3$, is similar, butit is used for testing the status of \.K and~\.V instead of\.S and~\.N. For example, a command having $\.{MOD}=1010$,$\.{OP}=3$, $\.A=1$, and $\.{SRC}=1$ adds the current overflow bit to thedestination register. (Please take a moment to understand whythis is true.)We have now described all the operations except those thatare performed when $\.{OP}=1$.As you might expect, our machine is able to do rudimentary arithmetic.The general addition and subtraction operators belong to this final case,together with various shift operators, depending on the value of \.{MOD}.Eight of the $\.{OP}=1$ operations set the destination register to a shiftedversion of the source value: $\.{MOD}=0$ means ``shift left~1,''which is equivalent to multiplying the source by~2; $\.{MOD}=1$ means``cyclic shift left~1,'' which is the same except that it also adds theprevious sign bit to the result; $\.{MOD}=2$ means ``shift left~4,''which is equivalent to multiplying by~16; $\.{MOD}=3$ means ``cyclicshift left~4''; $\.{MOD}=4$ means ``shift right~1,'' which isequivalent to dividing the source by~2 and rounding down to thenext lower integer if there was a remainder; $\.{MOD}=5$ means``unsigned shift right~1,'' which is the same except that themost significant bit is always set to zero instead of retaining theprevious sign; $\.{MOD}=6$ means ``shift right~4,'' which is equivalentto dividing the source by~16 and rounding down; $\.{MOD}=7$ means``unsigned shift right~4.'' Each of these shift operations affects\.S and~\.N, as in the case of logical operations. They also affect
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -