Close

Yet another memory cell - 2T

A project log for The Blinking Computer

An educational 16-bit CPU made from < 1000 transistors with lots of LEDs that anyone can build and learn from

Tony RobinsonTony Robinson 01/29/2019 at 09:257 Comments

So here I go again - here is another memory cell which I'd be pleased if the community could criticise.

For background, I want to build a discrete component CPU with enough LEDs so you can see how it all works and for it to be simple enough that others could build the design (e.g. for it to be a school 6th form project).  It has quite a few registers, about 8, so that you can see how a processor works (smaller would be possible but tortuous to program).   It's got a 16 bit instruction, data and address space to keep everything clean.   So, just for the sake of keeping things clean there are a lot of memory cells to build, something like 16 x 8 = 128 and this could dominate the component count and so be the major blocker to other people building this processor.

So I want the smallest number of components to build a memory cell.   The accepted smallest number is two, the standard DRAM design, in which a capacitor stores charge and is isolated by a MOSFET.   Whilst I applaud the efforts to recreate these in discrete components (look at https://hackaday.io/project/8449-hackaday-ttlers/log/44217-dynamic-ram-with-single-mosfet-per-bit) I really can't get my head around the precharge and the sharing of the bit line between read and write.  My CPU is meant as an introduction to everything from resistors through to compilers, so if it's not simple for me to understand then it's too complex for my processor.

As a result I've done a lot of thinking and here is a 2 transistor memory cell using a capacitor to store the charge:

Or, showing all the shared components, here it is as part of a register file:

DataInAll is the data line for one bit position across all registers/words.  It drives a NPN/PNP pair so that one conducts and the other doesn't.  So DataIn is connected to ground or +ve.   Provided WriteEnable is set low, then the capacitor keeps its charge, but if WriteEnable is set high then the capacitor will charge or discharge according to DataIn/DataInAll.   Reading is done with the MOSFET, so it doesn't suck current from the capacitor.   If ReadEnable is high then the state of DataOutAll is set by the state of the MOSFET, and the charge on the capacitor.   Only one register/word has ReadEnable set high, so only one can pull down DataOutAll.

From playing about, it seems that the capacitor is not needed, I can use the gate capacitance of the MOSFET.   So that's just two components for the memory cell.  I can't get lower than two so hopefully I can now move on to fixing  my diode ripple carry, the rest of the ALU, etc.

With no capacitor, things run fast.   Using a RPi I can put data on DataInAll, assert write enable, wait, ground WriteEnable, assert ReadEnable, wait, read the data, ground ReadEnable all at 200kHz.   That's as fast as I've got any of my memory cells to run, and is pushing the limits of WiringPi to set the GPIO (ultimately I'll abandon WiringPi).

Note that whilst I could use just the BJT and MOSFET (as above), the requirement that every state is visible means that I'm using the MOSFET to power a LED and running the read circuitry from that.   I want two read lines, so I have the basic BJT and MOSFET as above (no capacitor) but then I'm using an LED two more BJT, one for each read line.   So that's 5 components in total, not 2 as above, but a big improvement on the 21 components of my last written up memory cell.

Discussions

Tony Robinson wrote 01/30/2019 at 22:53 point

Thanks a lot @matseng for trying to replicate.!

At the moment I have no capacitor in there at all and have run 30ish cycles at 100s each.   I'm now testing 10 minutes but have only got through two cycles (of two memory cells) so far so it'll be the morning before I know.  I'm on standard breadboard (like https://www.amazon.co.uk/dp/B01M0QJTI5 only very cheap) so I'm also powering a row of 5 pins.

I also found a potential cheat, I was keeping the write data line at the data value so the signal could have leaked through.  I now set the data in to a random value after it has been written.   I am very suspicious of some other data leak at this stage.

The use of a S8050 was critical, my earlier 2N3904 wasn't good.   I really have no idea about the characteristics of these, they were just the cheapest NPNs I could find on ebay a few years ago so I had them to hand.

I do have LTspice installed now, I guess that's my best way to understand better what is happening.   I don't have a scope, I'm tempted by a very bottom of the range model, I used them at school and ugrad but that was almost 40 years ago.

UPDATE:  I ran for 60 read/write cycles at 10 mins a cycle last night without any error (but 60 data points isn't a lot).   At 1 hour a read/write cycle it errored after the first read.

  Are you sure? yes | no

roelh wrote 01/30/2019 at 15:39 point

Looks to me that it is possible to write a "1" (the BTJ supplies current out of its emitter). But it will not be possible to write a "0", because the BJT will only conduct in one direction. I think you should replace the BJT by a FET.

  Are you sure? yes | no

matseng wrote 01/30/2019 at 16:27 point

A NPN BJT works just fine with the polarities of emitter and collector reversed - as long as there's a current flowing into the base.  The gain will be a bit lower and some other parameters will be different, but I've reversed BJTs by mistakes several times and the circuit still works. At least for voltages below the avalanche voltage - I.E below like 10 volts.

  Are you sure? yes | no

roelh wrote 01/30/2019 at 17:37 point

Eh... Yes you are right. I actually also remarked this myself in this log: https://hackaday.io/project/160177-alu-in-dctl-technology/log/150452-full-alu-design.  It is almost never used in that way, so I my first reaction was that it is a useless configuration.

  Are you sure? yes | no

matseng wrote 01/30/2019 at 13:42 point

At first glance it actually looks kinda workable.  The leakage current of the WE-transistor might be an issue especially if a small storage cap is used (or none at all as suggested).

Do you have any plans for the refresh?  Done manually in CPU-code  with an interrupt running every few milliseconds that will do a read-write operation for single cell at each irq. Or using a separate refresh-logic controller.

Unless one have tens of minutes of storage time in the cap this would be a problem....

  Are you sure? yes | no

Tony Robinson wrote 01/30/2019 at 16:47 point

I have a quite a few models of BJT and there's definitely a significant difference in charge leakage.   I designed the circuit using a 100nF capacitor and whatever BJT I had to hand, and that would keep charge for over a day, just manually setting the inputs and visually looking at the LED on the output.   I then RPied it and that's when I found the leakage of the S8050 far superior.   It runs at 250kHz read and write cycle using random data and it'll run to a period of over 1 minute, but it would be good to find out when it breaks, I'll edit this answer when I know.   I figured that 10 minute refresh is fine for me and I think I have it.

  Are you sure? yes | no

matseng wrote 01/30/2019 at 18:17 point

What caps are you using?  I tried with a 1uf MLCC X7R,  100n X7R and 1n C0G with  both a 2n7000 and a 2n7002 all tests freeformed to reduce any leakage in the breadboard or pcbs.  I just barely got up to 15 minutes....

  Are you sure? yes | no