youtube video: https://youtu.be/XwtVsd5trLk test program error output screenshot: https://www.outerworldapps.com/pdp8v/alu_yt_pt1_abterr.png - blue background signals are being generated by raspi, sent via paddles to ALU board tubes - red background signals are what should be being generated by the ALU board tubes, they get compared to what the raspi is actually receiving on the paddles and any differences result in an error printed near the top - black background signals are being generated by raspi but aren't used by tubes crudely drawn gate schematics: https://www.outerworldapps.com/pdp8v/alu_yt_pt1_diag1.png https://www.outerworldapps.com/pdp8v/alu_yt_pt1_diag2.png online source file: https://github.com/mrieker/pdp8v/blob/github/modules/alu.mod online report file: https://www.outerworldapps.com/pdp8v/alu.rep.txt 02:26 test command line: ./aluboardtest -verbose -page -mult alu -verbose : print each test cycle out -page : start each print at top of page -mult : use the multi-board test function instead of individual board test alu : the paddles are plugged into the ALU board There are actually 2 tests for individual boards the -mult option says use the test that also works for multi-board sets, which gives better error messages Without -mult, it uses a custom test and the messages aren't that good. These are older tests that, while they still work, aren't that spiffy. So here I am using the -mult option to select the multi-board test even though I have just one board. The multi-board test can run with any non-empty set of boards plugged into the paddles. To plug more than one board into the paddles, you need a backplane. 02:42 it stopped on cycle 19: alu ---------------- cycle 19 end of 1.9 cps hwacon=850C1830 smacon=850C1830 adiff=00000000 hwbcon=60C58300 smbcon=60C58300 bdiff=00000000 hwccon=0D9B0808 smccon=0D9A0808 cdiff=00010000 _aluq[0] << errant bus pin hwdcon=00200000 smdcon=00200000 ddiff=00000000 PIN C17 (_aluq[0]) is HIGH should be LOW << error message A:952C58B0 B:62C58B10 C:0D9A0888 D:1FA45200 FETCH - - DEFER - - - EXEC * - - INTAK - << simulated PDP/8 state IR * * * GRPA1 * IOT2 - TAD3 - << more simulated state MQ * * * * - * * * * - - * 7571 MQL * << simulated MQ (memory buffer) value ACQ - - - - - - - - - - - - 0000 LNQ - << simulated AC,L (accumulator,link) values MAQ * * * - - * * * * - * - 7172 << simulated MA (memory address) value PCQ - - - - - - - - - - - * 0001 << simulated PC (program counter) value ACQZERO * GRPB_SKIP - INTRQ - IOSKP * CLOK2 - RESET - << other simulated bits ALUA_M1 * ALUA_MA - ALUA_MQ0600 - 1107 - ALUA_PC0600 - 1107 - << simulated control signals ALU_ADD - ALU_AND - INC_AXB - ALUB_AC * ALUB_M1 - ALUB_1 - << more simulated control signals ALUQ * * * * * * * * * * * * 7777 ALUCOUT - NEWLINK * << what the resultant ALU output should be 0.7777 = M1.M1/7777 ^ AC/0000 + 0 << ALU formula being computed DFRM - JUMP - INTAK - IOINST - MREAD - MWRITE - << more simulated control signals AC_ALUQ * AC_SC - LN_WRT * MA_ALUQ - PC_ALUQ - PC_INC - << more simulated control signals 04:25 opcode 7172 = CLL CMA CML RTR The only thing we care about here is how it is computing the ALUQ[00] output, So we can disregard the CLL, CML and RTR parts (rotate is not done by the ALU) and we don't care about the link bit. We only have to pay attention to the CMA part. And we can see that in the formula in the display above: 0.7777 = M1.M1/7777 ^ AC/0000 + 0 M1.M1/7777 means it is putting a constant -1 (7777) in the ALU A input. AC/0000 means it is putting the AC of all zeroes in the ALU B input. The 0 by itself on the end is the carry input to the computation. 0.7777 is the result of the computation. 04:46 what the ALU output should be And the display shows us what the ALU output should be: ALUQ * * * * * * * * * * * * 7777 ALUCOUT - NEWLINK * _ALUQ is active low, and _ALUQ[00] is the low-order bit, which should be LOW, but the error message says it is HIGH PIN C17 (_aluq[0]) is HIGH should be LOW 05:42 open kicads/alu/alu.rep file Look for line beginning with 0._aluq There are two: 0._aluq/alucirc[11:6]5 << this one is bit 0 of _ALUQ[11:06], ie bit 06, so we don't want this one 0._aluq/alucirc[5:0]5 << this one is bit 0 of _ALUQ[05:00], ie bit 00, so this is the one we want So here is that entry: 0._aluq/alucirc[5:0]5 out: J114 12.9,10.1 4L-U3A => Q.0._aluq/alucirc[5:0]5 => J4 11.2, 0.2 Conn/ccon<17> in: D610 12.1,10.1 <= Q.0.alu_andb/alucirc[0:0]1 and D611 12.1,10.3 <= Q.0.aandb/alucirc[11:0]2 or D613 12.1,10.5 <= Q.0.alu_addb/alucirc[0:0]1 and D614 12.1,10.7 <= Q.0.axbxorc/alucirc[11:0]5 or D616 12.1,10.9 <= Q.0.grpa1qb/alucirc[0:0]1 and D617 12.1,11.1 <= Q.0.axbxorc/alucirc[11:0]5 07:15 locate the gate output and measure The alu.rep entry says the gate's output is on J114 (always the top of the 3 pins), and is 12.9" over from left edge, and 10.1" down from top edge 08:20 look in modules/alu.mod source file for the equation for _aluq[00]: _aluq[05:00] = ~ (alu_andb & aandb[05:00] | alu_addb & axbxorc[05:00] | grpa1qb & axbxorc[05:00]); ...and we can see it closely resembles the above entry in the alu.rep file. 10:40 measure all the voltages on the inputs to the gates: in: D610 12.1,10.1 <= Q.0.alu_andb/alucirc[0:0]1 << -2.7V => 0 and D611 12.1,10.3 <= Q.0.aandb/alucirc[11:0]2 << -2.7V => 0 or D613 12.1,10.5 <= Q.0.alu_addb/alucirc[0:0]1 << -1.0V => 0 and D614 12.1,10.7 <= Q.0.axbxorc/alucirc[11:0]5 << -4.8V => 0 or D616 12.1,10.9 <= Q.0.grpa1qb/alucirc[0:0]1 << +6.8V => 1 and D617 12.1,11.1 <= Q.0.axbxorc/alucirc[11:0]5 << -4.8V => 0 16:00 what do those vales mean? We are computing ALUA=7777 xor ALUB=0000 => ALUQ=7777 which is _ALUQ=0000 18:42 what does each input do? Q.0.alu_andb/alucirc[0:0]1 << -2.7V => alu_andb = 0 : OK - we are not doing an AND function and Q.0.aandb/alucirc[11:0]2 << -2.7V => aandb = 0 : - doesn't matter or Q.0.alu_addb/alucirc[0:0]1 << -1.0V => alu_addb = 0 : OK - we are not doing an ADD function and Q.0.axbxorc/alucirc[11:0]5 << -4.8V => axbxorc = 0 : - doesn't matter or Q.0.grpa1qb/alucirc[0:0]1 << +6.8V => grpa1qb = 1 : OK - we ARE doing a Group 1 instruction (CMA) and Q.0.axbxorc/alucirc[11:0]5 << -4.8V => axbxorc = 0 : BAD - because axbxorc = ALUA[00] xor ALUB[00] xor CarryIn should be 1 21:50 How is axbxorc derived - look in alu.mod source file: axbxorc = ~ (~ (axorb | cin) | axorb & cin); For what we are doing with bit 0 (CMA with AC=0000): axorb[00] = 1 cin[00] = 0 (because we are not incrementing as would be the case for CMA IAC instruction) So we should have axbxorc[00] = 1, but we measured it to be -4.8V which is a 0. 24:50 Find axbxorc[00] on the board by looking in alu.rep for line beginning with 0.axbxorc: Of course there are two to choose from: 0.axbxorc/alucirc[11:0]2 0.axbxorc/alucirc[11:0]5 The little numbers on the end, eg 2 and 5, will tell us which is correct. We want the larger number because it is the topmost level gate of the equation. The entry ending with 2 is that inner gate '~ (axorb | cin)' that we don't care about for now. So that means we want entry 0.axbxorc/alucirc[11:0]5: 0.axbxorc/alucirc[11:0]5 out: J115 12.9, 8.6 3L-U7A => Q.0.axbxorc/alucirc[11:0]5 => D614 12.1,10.7 D2_2.0._aluq/alucirc[5:0]5<1> => D617 12.1,11.1 D3_2.0._aluq/alucirc[5:0]5<1> in: D605 12.1, 8.6 <= Q.0.axbxorc/alucirc[11:0]2 or D607 12.1, 9.0 <= Q.0.axorb/alucirc[11:0]3 and D608 12.1, 9.2 <= I14/dcon inc_axb[0:0] 30:05 D605 << +7.0V which is a strong logic '1' 30:15 That is sufficient to force the output signal to be logic '0', but it should be a logic '1' So the input signal to D605 is incorrect. 30:57 How is the signal to D605 derived? Looking in the alu.rep file, shows D605 12.1, 8.6 <= Q.0.axbxorc/alucirc[11:0]2 So it is the funky little 0.axbxorc/alucirc[11:0]2 gate that we ignored earlier. 31:40 Look back at the alu.mod source file: axbxorc = ~ (~ (axorb | cin) | axorb & cin); And we can see that axbxorc...2 = ~ (axorb | cin) 32:15 What should the values of that little equation be? axorb[00] should be '1' because we are doing a CMA instruction on an accumulator with bit 00 = 0 cin[00] (carry input to bit 0) should be '0' because we are not doing an IAC instruction 34:40 Look in alu.rep report file for that gate so we can measure it: 0.axbxorc/alucirc[11:0]2 out: J116 12.9, 5.6 2L-U7A => Q.0.axbxorc/alucirc[11:0]2 => D605 12.1, 8.6 D1_1.0.axbxorc/alucirc[11:0]5<1> in: D601 12.1, 5.6 <= Q.0.axorb/alucirc[11:0]3 or D603 12.1, 6.0 <= I14/dcon inc_axb[0:0] We can see that D601 is for the axorb[00] signal. From our reasoning above, we expect it to be a logic '1', ie, > +3V. D603 is for the inc_axb signal (which means increment a xor b). It comes from the paddles on pin D14. From our reasoning above, we expect it to be a logic '0', ie, < +0.7V. 37:00 What do we actually get for inputs? D601 +0.3V logic '0' = A[00]=1 xor B[0]=0 should be '1' - BAD D603 +0.05V logic '0' = carry input should be '0' - OK 41:25 Look in alu.rep report file for signal that feeds D601, namely 0.axorb/alucirc[11:0]3, so we search for line beginning with 0.axorb: 0.axorb/alucirc[11:0]3 out: J84 12.9, 7.1 3L-U3A => Q.0.axorb/alucirc[11:0]3 => D601 12.1, 5.6 D1_1.0.axbxorc/alucirc[11:0]2<1> => D607 12.1, 9.0 D2_1.0.axbxorc/alucirc[11:0]5<1> => D521 13.1,12.0 D2_1.~0.cin/alucirc[1:1]3<1> => D385 10.7,12.0 D_4.0._cin_inc_04/alucirc[0:0]2<1> in: D377 12.1, 7.1 <= Q.0.aandb/alucirc[11:0]2 or D379 12.1, 7.5 <= Q.0._alua/alucirc[6:0]5 and D380 12.1, 7.7 <= Q.0._alub/alucirc[0:0]3 We know from above that J84 output is +0.3V (logic '0') which is wrong. What are the diode inputs? D377 +0.5V logic '0' aandb[0] should be '0' - OK or D379 -1.1V logic '0' _alua[00] (active low alu A input) should be '0' - OK and D380 +2.1V logic '1' _alub[00] (active low alu B input) should be '1' - OK Given that all the inputs are correct, the gate should be outputting a '1'. Since D379 is missing, that D379 input looks like a '1', so the gate is outputting a '0'. Putting the diode in there should fix it, stay tuned for part deux.