Grid Based Digital Logic (Duodyadic Tiles)
C, 332 309 272 270 266 259 247 225 bytes

#define C(x)*c-x?
i,k,T,L,m;f(c,t,l)char*c,*t,*l;{while(L=l[i]){for(k=0;T=t[k];c++)L=C(49)C(43)C(92)C(85)C(41)C(33)C(38)C('|')C(94)T=48:(T^=L-48):(T|=L):(T&amp;=L):(T^=1,L^1):(T=L):T:(m=T,T=L,m):L:(T=49),t[k++]=T;c++;l[i++]=L;}}

View results online here!
This defines a function void f(char*, char*, char*), which should take the board as its first input, then the top row of input, and then the left row of input.
Here's what I used to test it:
#include &quot;stdio.h&quot;
int main() {
    char buf[1024],top[33],left[33];
    /* Copy and paste an example circuit as the first input,
       and put a 'Q' immediately after it. 
       Note that the Q is never touched by the function f, and is used
       solely as a delimiter for input. */
    scanf(&quot;%[^Q]Q &quot;,buf);
    /* Then enter your top inputs */
    scanf(&quot;%[01]%*[^01]&quot;, top);
    /* Then your left ones */
    scanf(&quot;%[01]&quot;, left);
    /* OUTPUT: Bottom\nRight */
    f(buf, top, left);
    return 0;
}

Thus, by inputting Sp3000's 2-bit multiplier:
UUUU))))
UU++)))&amp;
UUU+)  U
UU++&amp;))U
U++&amp;+)^U
U)&amp;\&amp;)UU
   U+^UU
   \&amp;UUUQ
11110000
00000000

We get:
00001001
11111111

On another note, with Sp3000's half adder in mind, I'd like to see a full adder... One of you guys did it! I don't think the system stands on its own as a programming language, but it's been very interesting. This seems like an excellent target for metagolf, though!
A Short Explanation:
Here's the unraveled, commented code:
/* We define the first half of the ?: conditional operator because, well,
   it appears over and over again. */
#define C(x)*c-x?
/* i,k are counting variables
   T,L are *current* top and left inputs */
i,k,T,L,m;
f(c,t,l)char*c,*t,*l;{
    /* The outer loop iterates from top to bottom over l and c */
    while(L=l[i]){
        /* Inner loop iterates from left to right over t and c */
        for(k=0;T=t[k];c++)
            /* This line looks awful, but it's just a bunch of character
            comparisons, and sets T and L to the output of the current c */
            L=C(49)C(43)C(92)C(85)C(41)C(33)C(38)C('|')C(94)T=48:(T^=L-48):(T|=L):(T&amp;=L):(T^=1,L^1):(T=L):T:(m=T,T=L,m):L:(T=49),
            /* Write our output to our input, it will be used for the next row */
            t[k++]=T;
        c++; /*Absorbs the newline at the end of every row */
        /* Keep track of our right-most outputs, 
        and store them in the handy string passed to the function. */
        l[i++]=L;
    }
    /* Bottom output is now stored entirely in t, as is right output in l */        
}

We iterate over c, left to right (then top to bottom), rewriting the t inputs each time and pushing out a right-most output which is shoved into the l string. We can imagine this as replacing the top row of c with 1's and 0's iteratively, and keeping track of the bits that are pushed out at the right.
Here's a more visual sequence, row by row:
 111                                  
1&amp;+^  =&gt;  110 -&gt;0  =&gt;     -&gt;0  =&gt;     0 Thus, &quot;01&quot; has been written to l,
1+&amp;+     1+&amp;+         110 -&gt;1         1
                                  110   And &quot;110&quot; is stored currently in t.

This obviously gets more complicated with different symbols and sizes, but the central idea holds. This works only because data never flows up or left.