Outtakes

Here are all the dead ends I though about and abandoned or just plain mistakes I made - there's at least as much to be learned from this section as the rest:
  • Transistors or relays? (http://www.electronixandmore.com/projects/relaycomputertwo/index.html).  Relays are more physical, and easier to understand how they work, but they run too slow, are unreliable and cost too much (even the cool miniture enclosed relays like these).
  • Bit serial or bit parallel ALU?  For most if this project's life, until about Summer 2016, I assumed bit serial as I'd imagined that the ALU was a major contributor to the transistor count.  Now I've discovered the two transistor XOR and I believe that the six 16 bit registers are going to dominate.  The bit serial ALU would have been pretty to watch the first time, but would have soon become tedious.   Doing everything in parallel will keep the attention span on the flashing lights better
  • Forth or Lisp for the lowest level language?   I went with Forth because it is simpler to implement.
  • Support C?   There are a huge number of choices (see below), none are easy, it took a while to decide not to support C (at least until everything else is running).
  • I'm using Transistor Resistor Logic using bipolar transistors - don't get confused by FET/unipolar designs on the web.
  • Getting a clear understanding of the inner interpreter for Forth took a long item - see the refs on the Forth page for a clear explanation (so many of the explanations on the web aren't clear).
  • I nearly implemented a processor where one register held the address of the memory to be read/written - like the RCA 1802.   The advantage is that memory to CPU is well separated from register to register, the disadvantage is that lots of register shuffling is needed which I expected to be very slow.
  • The Carry function occurs twice, once to compute the Carry Out, Co, from Ci, A and B in the ALU, and also to compute both AND (Ci == 0) and OR (Ci == 1).  The required joint truth table for this function is:
     Ci   A B SUM Co
     0 0 0 0 0
     0 0 1 1 0
     0 1 0 1 0
     0 1 1 2 1
     1 0 0 1 0
     1 0 1 2 1
     1 1 0 2 1
     1 1 1 3 1
    Measuring the Vin/Vout response of my NPN transistors shows that below 0.5V they are off and above 0.7V they are on.   So it was very tempting to wire all three inputs via large resistors to the base of a NPN and wire the base to ground with a smallish resistor.   The idea was that when the sum was 1 the input would be 0.4V and when 2 0.8V so clearly outside of the transition region.   It did work, using 10k as the input resistors and 3.3k from base to ground, however the gap was only 0.56V to 0.69V, the output was inverted and it relies on low impedance sources.  For the sake of a couple of extra transistors I decided it wasn't worth breaking with standard transistor/diode/resistor logic.   The One Transistor Full Adder is an extreme form of this thinking.
  • 14Jan17 - My first memory design failed, it didn't disable writes correctly.   I spent too long in optimising this design thinking it worked whereas I hadn't tested putting a signal in with writes disabled.   The page on the broken design is Memory Cell FAIL.
  • 22Feb17 - The first version of the ALU is at ALU V1 - there's nothing wrong with it, I just wanted something easier to explain.
  • 22Feb17 - My (somewhat jumbled) thought process that led to the diode carry is at Carry Propagation
  • 15May17 - Should read and increment be the inverse of write and decrement?    Until last year this was true and I had true PUSH and POP instructions.   This has the huge advantage that the machine code looks nice and clean.   However, if we have read and increment we then need decrement and write and that means we can no longer overlap the ALU doing a decrement with the memory access (the decrement must finish before the memory access starts).   As a consequence the control logic for read would end up being very different to write and it wouldn't' be efficient.   Doing memory access then inc/dec doesn't look quite as clean, but keeps the ALU and memory unit running at full speed (assuming they both take about the same amount of time) and so is efficient for long runs of PUSH/POP
  • 17Jul17- "Use one bit for set flags?  Then you can explicitly not set flags on I = *P++ but set them on a pop if you want?  Currently doing a few pops then adding zero to set flags." abandoned because flags are set by the ALU not by assign.
  • 06Aug17 8 bit processor.  At face value it would halve the transistor count, which is the biggest barrier to mass adoption.   However, the program counter and instruction register would still be 16 bits.   Anything that wanted to address the main memory space, like P = *E++ or the C and D stacks would also have to be 16 bits.  So that just leaves A and B, and the thought of a segmented memory space (256 lots of 128 words, so every function would have to be less than 128 words long) to deal with.   If I seriously want to reduce the transistor count then memory mapping all registers has to be the way to go, but it's no longer very dydactic.