DEV Community

Rondo
Rondo

Posted on Originally published at dev-rondo.com

My Nand2Tetris Journey #3 - Building Bit, Register, RAM, and PC

What I Built

  • Bit(Single-bit register), Register(16bit - 1 word), RAM8-RAM16K, PC(16bit Program Counter)

What I Learned

  • What clock, bit, register, RAM and PC are
  • Sequential logic in computer system
  • How just a little DFF can be RAMn and PC
  • Feedback
  • Addressing in RAM
  • Memory hierarchy
  • Propagation Delay in Combinational Logic
  • Why clock matters and why overclock is dangerous

Reflection

This chapter was much harder than Chapter 2. I think it was because the concept of the "past" appeared for the first time here.

And I found it really interesting to see how the concept of the past could be developed into a register, and then further developed into a storage device called RAM.

However, my progress was quite slow because I had one big misunderstanding. Maybe because I had been thinking too much like a software developer, I thought of in and out like a function.

For example, when I thought about Bit, I imagined something like in, in, in, in, in..., where values kept entering a function at very short intervals, got divided depending on load, and then came out through out. In other words, I imagined it like data packets being transmitted. But this was about hardware, and the data wasn't moving around like packets. It simply existed as electrical signals on wires.

Once I understood this concept, the chapter no longer felt that difficult. In the end, the key point was that the DFF's out is the in from t-1, and because of that, it can store the past, which makes "memory" possible. Since the DFF introduces a one-cycle delay, the current out does not determine itself immediately. Instead, it is used to determine the out of the next cycle, which makes stable feedback possible.

I was also able to properly understand each component.

The clock is simply a dumb guy that can only go tick-tock (but a very important one, because it defines the clock cycle).

The DFF is a guy that sends the in of the current clock cycle to the out of the next cycle.

Bit is a single-bit register that either reuses the current out or updates it with in, depending on load.

A Register is a group of Bits that can handle one word (the unit of data handled by the computer system, which is 16 bits here), sharing the same load.

RAM is basically a group of Registers, with an address deciding which Register should be read or written. When RAM becomes larger, it can be built by combining smaller RAM chips from the previous level. When combining eight RAM chips, the upper 3 bits starting from the MSB can be used to select which lower-level RAM to access. What about the remaining address bits? They can simply be passed down to the lower-level RAMs.

For example, when building RAM512, the upper 3 bits starting from the MSB can be used as the sel input of the DMux and Mux, while the remaining bits are passed down. Then, inside RAM64, the upper 3 bits of those remaining bits are used as sel again, and so on. As a result, the total address width becomes 9 bits. (RAM512 -> RAM64 -> RAM8, using 3 bits at each level.)

One of the most important things I learned while building RAM was that when handling "read with Mux, write with DMux," the value distributed by the DMux should be load. The same in can be given to every Register, while load is distributed through the DMux. As a result, only the Register (or RAM) that actually needs to be updated receives load=1.

I also had an interesting experience with load while implementing the PC. I initially used Or gates so that the internal Register's load would become 1 whenever any of reset, load, or inc was 1.

But after looking at it again, I realized that this wasn't necessary at all. I could simply keep the Register's load fixed to 1, and it still worked perfectly. Since the value had already been selected correctly through the Muxes in the previous stages, storing it every cycle didn't cause any problem.

There was also something that wasn't directly included in the project, but I became curious about it and looked it up separately.

It was called Propagation Delay, and the idea is that Combinational chips such as the ALU keep calculating continuously whenever their inputs change.

However, real electrical signals do not become stable immediately when their values change because of factors such as distance and resistance. Because of this, an ALU may temporarily produce garbage values after its inputs change.

So hardware designers make sure the clock period is long enough for the ALU's result to become stable even under the worst conditions.

Simply put, even if the ALU's output temporarily becomes incorrect during a clock cycle after its inputs change, the clock period is designed so that the value becomes stable before the next clock edge arrives.

This is one of the reasons why sequential architecture can synchronize the entire computer.

And this also helped me understand why overclocking can be dangerous. If we arbitrarily shorten the clock period that the hardware was designed for, the next clock edge may arrive before the ALU's output becomes stable. And then? The system will obviously face unexpected results.

In conclusion, this chapter was difficult, but it was also the most interesting one so far.

Let's keep moving on.

Top comments (0)