Search code examples
nand2tetris

Nand2Tetris-Obtaining Register from RAM chips


I've recently completed Chapter 3 of the associated textbook for this course: The Elements of Computing, Second Edition.

While I was able to implement all of the chips described in this chapter, I am still trying to wrap my head around how exactly the RAM chips work. I think I understand them in theory (e.g. a Ram4K chip stores a set of 8 RAM512 chips, which itself is a set of 8 RAM64 chips).

What I am unsure about is actually using the chips. For example, suppose I try to output a single register from RAM16K using this code, given an address:

    CHIP RAM16K {
        IN in[16], load, address[14];
        OUT out[16];
    
        PARTS:
        Mux4Way16(a=firstRam, b=secondRam, c=thirdRam, d=fourthRam, sel=address[12..13], out=out);
    
    And(a=load, b=load, out=shouldLoad);
    
    DMux4Way(in=shouldLoad, sel=address[12..13], a=setRamOne, b=setRamTwo, c=setRamThree, d=setRamFour);
    
    
 RAM4K(in=in, load=setRamOne, address=address[0..11], out=firstRam);
 RAM4K(in=in, load=setRamTwo, address=address[0..11], out=secondRam);
 RAM4K(in=in, load=setRamThree, address=address[0..11], out=thirdRam);
 RAM4K(in=in, load=setRamFour, address=address[0..11], out=fourthRam);
 }

How does the above code get the underlying register? If I understand the description of the chip correctly, it is supposed to return a single register. I can see that it outputs a RAM4K based on a series of address bits -- does it also get the base register itself recursively through the chips at the bottom? Why doesn't this code have an error if it's outputting a RAM4K when we expect a register?


Solution

  • It's been a while since I did the course so please excuse any minor errors below.

    Each RAM chip (whatever the size) consists of an array of smaller chips. If you are implementing a 16K chip with 4K subchips, then there will be 4 of them.

    So you would use 2 bits of the incoming address to select what sub-chip you need to work with, and the remaining 12 bits are sent on to all the sub-chip. It doesn't matter how you divide up the bits, as long as you have a set of 2 and a set of 12.

    Specifically, the 2 select bits are used to route the load signal to just one sub-chip (ie: using a DMux4Way), so loads only affect that one sub-chip, and they are also used to pick which of the sub-chips outputs are used (ie: a Mux4Way16).

    When I was doing it, I found that the simplest way to do things was always use the least-significant bits as the select bits. So for example, my RAM64 chip used address[0..2] as the select bits, and passed address[3..5] to the RAM8 sub-chips.

    The thing that may be confusing you is that in these kinds of circuits, all of the sub-chips are activated. It's just that you use the select bits to decide which sub-chip's output to pass on to the outputs, and also as a filter to decide which sub-chip might perform a load.

    As the saying goes, "It's turtles (or ram chips) all the way down."