Week 3 — 3/2/20 to 3/8/20
Table of Contents
What’s up humans and other creatures from the deep, hope everybody is staying active and mentally healthy while locked up inside by the iron decree of the Californian gubernatorial governance. Today’s going to be about the registers, the second of the seven components in the CPU.
The style of this week’s blog post and the blog posts from here on out are going to be yet again a bit different from last week’s post, since I think dumping theory into a blog post is not an extremely good idea. Inspired by Ravit’s blog post structure, I’m going to try keeping a high-level blog post and a separate documentation file for more in-the-weeds technical details; I’ll try to make the blog post as brief and high-level as possible, and also keep the documentation fairly terse, in an effort to deliver these blog posts on time.
Goals for topics to discuss in this blog:
– Theory for registers and related components
– Building process and modifications to Eater’s register design
– Previewing next week plans
A preview of the completed registers module, with the clock and testing module:
I’ll keep a theory section still to explain roughly what’s going on inside the modules, so you can get an intuition on the operation of the modules without necessarily needing to read the documentation file.
Last week we looked at the SR latch, which is a circuit that persistently stores a bit of data, allowing you to change the data stored by means of two inputs (S and R inputs, making the data 1 or 0 respectively).
The D flip-flop is a common extension of the SR latch. The purpose is the same — store a bit of data; however, the input mechanism is modified. Instead of two inputs S and R, we have an alternate pair of inputs, which are the “D” input and “EN” input. See here in the schematic that the D flip-flop contains the SR latch at the end, adding in some additional input modification at the beginning.
The “D”, or data, input is the bit of data to be stored, either a 0 or 1. The “EN”, or enable, input tells the D flip-flop to store the bit of data coming in from the D input (we don’t always want to be storing the data from D, so it’s helpful to have this EN control input).
The benefit of having the D flip-flop is twofold: first, it has a simpler input mechanism for the data, having only one input D to set the data stored, compared to the SR latch’s two inputs S and R. Second, it allows the data to be stored only when we ask it to, which allows us to synchronize it with the clock of the CPU.
We’ll see how we can apply this data storage and input-restriction scheme from the D flip-flop in the construction of our registers in the next section.
The big component for the week — registers! First off, what are registers, and why do we need to build them?
Registers are a storage mechanism for the CPU, storing small amounts of data that always need to be kept on hand for the CPU’s operation. In our case, each register stores a single number, represented by 8 bits of data.
Some examples of registers that we’ll build are the instruction register, storing the next instruction to carry out, and the A and B registers, storing the numbers that we want to add in our ALU module.
Note that registers are fairly simple, and they don’t really have any more complex operation than storing data and outputting stored data. We don’t need to design a register specifically as an instruction register, or an A or B register — any register can effectively be used in place of any other register, barring some small modifications on where the inputs and outputs are connected to.
Okay, with the function of the registers set down, how should we go about making these registers? The D flip-flops we described earlier each store 1 bit of data; we can put together 8 D flip-flops to store 8 bits of data, forming the base functionality of a register.
As it stands in our current formulation, a register consisting of 8 D flip-flops has the capability to read in 8 bits of data, and have an option to either hold on to its current stored value, or copy in the data from the 8 input bits. In addition, we have 8 bits coming out of the register that show what information is being stored in the register.
The CPU Bus
With the idea that the registers are storing numbers that other components in the CPU need to use, we’ll zoom out a bit to take a look at the bigger picture of how things in the CPU connect together, through a central communication line called the bus.
The bus is the heart of the CPU communication system — each component has a connection to the bus. Notably, this means that every component can communicate with every other component through the bus, which allows us not to run individual connections between every pair of components.
The caveat is that, since the bus is a shared communication medium that all components are attached to, only one component can send an output onto the bus at one time. In addition, all components need to have the capability to enable or disable reading inputs from the bus, if they’re not the target recipients of the output currently on the bus.
Input and Output Gating
Having established the necessity for each component to control its input and output to the bus, we need to find a mechanism for controlling each one, i.e. “gating” the inputs and outputs.
For input gating, we make use of a “load” signal to tell the component to read from the bus. At every clock cycle, if the load signal is high, then a register’s D flip-flops will read input from the bus, into its “D” input. If the load signal is low, then we’ll simply pass the output of the D flip-flop back into the D input, keeping the value the same (instead of loading input from the bus).
Image credit: open4tech.com
For output gating, we use a construction called a tri-state buffer. The tri-state buffer takes in a data signal, 0 or 1, and also an “enable” signal. If the enable signal is high, then the output is put onto the bus, but if the enable signal is low, the tri-state buffer effectively disconnects from the bus, not putting any signal on the bus.
Building the Registers
So we’ve just run through the theory on what a register needs to do, which is to store 8 bits of data, and have inputs and outputs that can be disconnected based on load and enable signals.
I originally wanted to see if I could build the registers without using ICs, as I’m trying to rely on pure logic gates as much as possible (I suspect now that, in general, doing so would be infeasible in terms of space, if not cost). I made some schematics for how to construct the D flip-flops and the input and output gating, which I put in the documentation. However, after planning the build out, choosing to build the 3 registers that we need to build without using ICs comes out to about 6 breadboards in terms of space usage, and around $90 in terms of cost. I’ve instead opted to use the 74LS173 ICs, which provide a nearly-equivalent functionality, as D flip-flops with input and output gating. This lets us actually compress the 3 registers down into a single breadboard and costs about $10, which I thought was a good efficiency tradeoff for having to use ICs.
I’m happy enough to use ICs for now, as long as I know exactly how to build the circuit without them, so if I do need to use ICs in the coming weeks, I’ll create planning schematics for how to construct the circuit with logic gates. Hopefully it’ll also be an interesting exercise in observing just how much more efficient modern semiconductor manufacturing is compared to people trying to build things with logic gates (and this is just the tip of the iceberg).
I haven’t really run into any major engineering challenges other than trying to figure out whether the modifications I made (discussed below) would actually work with the rest of the system, so there’s no engineering challenges section this week.
As much as I’ve been using Eater’s designs as reference, there are cases where I would prefer a different setup than what he has chosen.
The A and B registers are used in the sum operation for the CPU, and they must be connected to the ALU directly, since the ALU needs to be able to see the contents of both the A and B registers simultaneously, without going through the bus. Eater chooses to connect the A register back to the bus for certain CPU commands, but I’ve taken a look ahead at these commands and decided I could implement them a different way, so I chose not to connect the A register back to the bus. In my design, then, neither the A nor B register outputs back to the bus, so they do not have output gating.
I’m also trying to see whether I can make any improvements in the utilization of breadboard space, since if you’re not careful things can get fairly large/spread out. Eater chose to use one breadboard per register, but with the modification I made to the A register (not needing to connect it back), I managed to put all three registers (A, B, and instruction register) on a single breadboard.
Building a Testing Board
To test the registers, I needed to find some sort of way to give 8 bits of data to each register, and read the 8 bits of data coming out of each register. I don’t have any other components to provide 8 bits of data right now, so even if I made a bus to connect the registers to, I wouldn’t be able to test the registers. I built a small board here that can output 8 bits of data that are set to 0 or 1 based on a set of switches that you can toggle manually, and read in 8 bits of data that are coming from the registers.
The final products from this week are three registers, the A, B, and instruction registers, which each allow controlled 8-bit input from a bus, and store these 8 bits until needed by another part of the CPU. Modifications from Eater include compressing the three registers onto a single breadboard, and removing the requirement for the A register to output back onto the bus (allowing me to avoid using some ICs that Eater does). In addition, a testing circuit has been completed that can display 8 bits of data on LEDs, and can output an 8-bit number arbitrarily set by manual switches.
Here’s a demo of the operation of the registers, loading data in and reading in data from a register.
Computing for Coronavirus
I thought that now would be an interesting time to reflect on the motivation behind this project. At the outset, the goal of this project was so I could understand the hardware behind a CPU in depth and be able to implement it (even if it’s just at the breadboard scale), and try learning how to implement more efficient hardware (I chose machine learning since I know domain-specific hardware advancements are definitely helpful there, and I’m a bit more comfortable with the operators to implement). I’d also hoped to write a guide (and blogs) to help anyone who would be interested in learning about the same to be able to pick it up more easily, as a supplement to Ben Eater’s already excellent video series.
In short, the project is really about literacy in the hardware aspect of computing/CS, both for myself and for others. In my senior project proposal/defense to Mr. Brady, I touched upon the motivation for pursuing hardware improvements, or, effectively, the question of “why do we care to have faster/smaller computers at all?”
While I was browsing r/Coronavirus on Reddit, I found a cool initiative called Folding@home, or F@h. F@h crowdsources computing power from anyone who is willing to contribute; you don’t need to have a particularly powerful computer to help out. The computing power is used for helping researchers simulate protein folding, and recently, they’ve been devoting their computing resources to try to figure out possible candidate proteins of COVID-19 to target with drugs. That made me think a bit about how useful improved computing power would be here, where something like a mere 20% improvement in available computing power (either by making computers faster, or making them cheaper and more available) could mean developing a cure months faster. Of course, the improvement in computing power need not come from hardware (it could come from improved algorithms, etc.) but I thought it was a nice and topical example for why we might care about computing power.
Next Week Plans
Next week, we’ll be looking at the construction of the ALU, especially how you might go about trying to implement addition via logic gates. Hopefully this will shed some light onto how implementing mathematical operations in circuits works in general, which will be helpful for the ML operators module as well, later on.
I have been learning some of the theory a bit ahead of the scheduling of these blog posts, so I’ll see if I can start writing about the ALU portion in one or two days, and get the blog post out a few days after that. Aiming to get back on the schedule of one post per week since the start, which means I’ll be on a faster schedule for the next week or so. The content of the blogs should mostly be based on how quickly I can learn and build/test each component, so I won’t be skimming on much by trying to get these out faster (just have to focus a bit more).
That’s it for the registers post! I think I managed to get the blog post down to a more readable length, which I’m happy about. If you’re curious about the implementation of any of the circuit components, do check out the documentation, which has the schematics and some supplementary explanation with it.
Again, if you have any questions, let me know down in the comments section below. Hope you enjoyed this post. I think this terrible “like share subscribe” youtuber meme has gone on long enough, lol, so I’m stopping it now… But still, have a wonderful week and don’t forget to smile, alright — and I’ll see you in the next one.
Links to Previous Weeks: