Holding State
In the previous post, we discussed binary numbers and how the presence or absence of electricity in a circuit can be modeled as a 0 or a 1 respectively.
However, a fundamental problem with electrical circuits is that they are transient. They can’t hold state of their own. For example, from one second to the next, a wire has no idea whether electricity passed through it in the second prior.
Let’s fix that problem with some logic gates. I’ll show you three different images showing different variations of the same circuit.
Source: CODE by Charles Petzold
The two logic gates being used in the above set of images are NOR gates. Here is the truth table for a NOR gate.
Source: CODE by Charles Petzold
Let’s look at image one first. The NOR gate on the left has an output of 1 because both its inputs are 0 initially.
If you close the gate on top, the output of the NOR gate on the right becomes 1 because both its inputs are now 0 and the bulb lights up.
Here’s the crazy bit(no pun intended): if you now open the gate on top, the bulb still remains lit!
Why? Because both the inputs to the NOR gate on the right are still 0, so the output remains 1. We just created memory in a circuit!
Now, no matter how many times you open or close the gate on top, the bulb will remain lit. The only way to turn the bulb off is to close the bottom gate while keeping the top gate open.
This circuit is typically called a flip-flop circuit. The circuit illustrated here is more commonly called a Reset-Set flip-flop (R-S flip flop). Here is another way to draw the circuit. The circuit remains the same, just with the light bulb removed and two outputs being shown, one for each NOR gate.
Source: CODE by Charles Petzold
Here is the truth table for the same:
Source: CODE by Charles Petzold
However, the R-S flip flop has an issue associated with it. If you look at the truth table, you’ll notice that if both the inputs are set to 1, the output is indeterminate.
To avoid this, we will use something called a level-triggered D-type latch. Here is the schematic.
Source: CODE by Charles Petzold
Notice that the right half of the diagram is the exact same as our original R-S flip flop. The left half has two additional AND gates connected to two inputs called the Data input and the Clock input.
The Data input can never provide the same input to both AND gates because it is connected to an inverter. The Clock input typically alternates between 0 and 1, and it serves to determine whether the current data input needs to be remembered or not.
Inputs OutputsD Clock Q Q_bar0 1 0 1 1 1 1 0 X 0 Q Q_bar
There is a difference between having a Clock input of 0 or 1. When the Clock input is 1, the outputs Q and Q_bar reflect the identity and inverse of D respectively. When the Clock input is 0, the input D does not matter and the outputs remain the same.
Let’s attempt to model the level triggered flip flop in code.
This is an IIFE (immediately invoked function execution). I’m using this to maintain an internal state for a function without exposing it to the global scope. You can read more about IIFE’s here.
The flipflop
function expects a data
and a write
parameter. The state
is only
overwritten if write
is 1. Great, we’ve figured out a
way to store a bit!
You can run the above code with functions like below:
levelTrigger.flipflop(0, 1)levelTrigger.flipflop(1, 1)levelTrigger.flipflop(0, 0)var result = levelTrigger.getState()
Assembling The Memory
Let’s take the fancy logic gate from the prior figure and represent it as a black box now. We’ll call what we have below a 1-bit latch.
Source: CODE by Charles Petzold
The DO in the above represents the state
variable
for us.
Now that we can store 1-bit values in a latch, we can store 8-bit values by storing 8 1-bit values in 8 separate latches. The only roadblock is if we have 8 of these latches, how do we differentiate between them?
Simple: we’ll use 3-bit binary numbers. The numbers 0 to 7 represent 8 different values and in binary they go from 000 to 111.
I’m sure you’ve guessed what we’re attempting to do by now. We’re trying to represent each of these functions in memory with the 3-bit binary number representing the memory address. (This is, obviously, a very simplistic model).
Unfortunately, JavaScript doesn’t allow memory access unlike C. For example, in C, you could get access to the address of a function pointer like so:
With JavaScript we’re going to fudge it a little bit. We’ll use a plain JS object to represent our internal memory. Not a bad approximation at all.
I’ve built upon the code we had initially, just replacing the
internal state
variable with a
memoryObj
This is the logic circuit representation of what we’ve built so far.
Source: CODE by Charles Petzold
It may seem like a massive jump, but look carefully at what the circuit does. There are 8 1-bit latches in the middle and there is a write signal and a data in signal being provided. The address is the 3-bit address representing each of the 8 latches.
The 3-to-8 decoder and 8-to-1 selector are complex logic gates that perform the functionality of targeting specific memory addresses based on the address signal being fed in to them. Something we easily accomplish in a programming language like JavaScript with the key-value pairs of an object.
If you want to understand what the 3-to-8 decoder and 8-to-1 selector do, read here and here. I’m going to skip over it because for our purposes, it is enough to understand that these are circuits through which we feed electric signals to map to a specific memory address.
The Size Of Memory
Let’s think about how much memory we have based on our previous example so far. We have the ability to store 8 1-bit values to give us a total of 8 bits.
What we built above is typically called an 8x1 RAM array. The reason we are limited to 8 bits is because we used a three bit memory address.
Since 2³ = 8, we have the general formula of:
2^n = Total Number Of Bits That Can Be Stored, where n = the number of bits in the memory address.
If we have a four bit memory address where each address can store 1 bit, we would have a 16x1 RAM array like below
Source: CODE by Charles Petzold
Now, if we had a 10 bit memory address, we could store 1024 separate bits because 2¹⁰ = 1024.
But, what if we could store more 8 bits in each memory address? Well, then we’d have a 1024 * 8 = 8192 total bits.
If we extend this, we could have a 16 bit memory address with 8 bits stored in each address.
Source: CODE by Charles Petzold
The 64K above actually represents 2¹⁶ = 65,536.
Visualizing Memory
Let’s take a moment to make an approximation of what memory “looks” like in a computer. We know we can reference different addresses in memory using an n-bit number, where n can be any number between and inclusive of 1 and 16.
If we were to physically represent this, it might look something like this:
Representing memory addresses as blocks
Each of the blocks in the column on the right represent a separate piece of memory. Each piece of memory is composed of 8 1-bit latches which we’ve already seen how to construct.
The column on the left represents the 3-bit address of each of the blocks. We can access the 8-bit number by accessing the memory address for that specific number.
Since we are using a JavaScript object to represent our internal
memory, we could access the memory like so:
memoryObj[address]
Automation
Okay, now that we’ve figured out how memory is built, let’s try to utilize the memory to perform some basic operations. Like addition, for example.
In the binary adder we built in the previous post, we had the ability to add two 8-bit numbers and get the result. Now, what if we want to add a series of 8-bit numbers and get the final result without having to worry about the intermediate result?
We can store every intermediate result in an 8-bit latch and keep updating the running total!
We already designed an 8-bit adder so we can keep feeding the intermediate result and the next number into the 8-bit adder so that we can keep updating the total.
PLEASE UPVOTE IF YOU FIND THIS HELPFUL.
• 11- Implementing a circuit using ROM modules. • 1-Build a new module which takes X...
Module 50: Using two 2-to-1 multiplexers, design a circuit which takes two signal bits, s, and so and connects x, to y, in the following way: X1 EECS 140/141 (Fall 2018)
Building and testing basic combinational circuits using Verilog HDL Description: Build and test the following circuits using gate-level modeling in Verilog HDL. 1. 3-input majority function. 2. Conditional inverter (see the table below: x - control input, y - data input). Do NOT use XOR gates for the implementation. x y Output 0 y 1 y' 3. Two-input multiplexer (see the table below: x,y - data inputs, z - control input). z Output 0 x 1 y 4. 1-bit half...
Building and testing basic combinational circuits using Verilog HDL Description: Build and test the following circuits using gate-level modeling in Verilog HDL 1.3-input majority function 2.Conditional inverter (see the table below: x - control input, y -data input). Do NOT use XOR gates for the implementation. Output 3. Two-input multiplexer (see the table below: x.y -data inputs, z- control input) Output 4. 1-bit half adder. 5. 1-bit full adder by cascading two half adders 6.1-bit full adder directly (as in...
The circuit below takes as input a four bit unsigned binary number A A2 A Ao and generates a single output F. Design the circuit where F will only be true if the decimal value of the input mod 3 is equal to 1 (F is true if the input mod 3- 1; F will be false otherwise). To implement F, you may use only the 8 x 1 multiplexor given below. You may not use any additional gates (such...
using python 3 notebook only 4.2 An ellipse is defined by the equation which is solved for y to give a function yx) for the ellipse. 4.1 " Define a function that takes x, a, b as input and returns y Make a plot of the full ellipse including all four quadrants using a-2 and b-1. Use a blue, dashed line. 4.2 Calculate the area under a quarter of the ellipse, use the top-right quadrant by approximating the quarter ellipse...
Assignment Predator / Prey Objectives Reading from and writing to text files Implementing mathematical formulas in C++ Implementing classes Using vectors Using command line arguments Modifying previously written code Tasks For this project, you will implement a simulation for predicting the future populations for a group of animals that we’ll call prey and their predators. Given the rate at which prey births exceed natural deaths, the rate of predation, the rate at which predator deaths exceeds births without a food...
Objectives You will implement and test a class called MyString. Each MyString object keeps track of a sequence of characters, similar to the standard C++ string class but with fewer operations. The objectives of this programming assignment are as follows. Ensure that you can write a class that uses dynamic memory to store a sequence whose length is unspecified. (Keep in mind that if you were actually writing a program that needs a string, you would use the C++ standard...
This C++ Program consists of: operator overloading, as well as experience with managing dynamic memory allocation inside a class. Task One common limitation of programming languages is that the built-in types are limited to smaller finite ranges of storage. For instance, the built-in int type in C++ is 4 bytes in most systems today, allowing for about 4 billion different numbers. The regular int splits this range between positive and negative numbers, but even an unsigned int (assuming 4 bytes)...
If you’re using Visual Studio Community 2015, as requested, the instructions below should be exact but minor discrepancies may require you to adjust. If you are attempting this assignment using another version of Visual Studio, you can expect differences in the look, feel, and/or step-by-step instructions below and you’ll have to determine the equivalent actions or operations for your version on your own. INTRODUCTION: In this assignment, you will develop some of the logic for, and then work with, the...