Project 1: Memorable Circuits

Some of the language below refers to programming problems. There are no programming problems on this project. Please ignore language that is obviously not applicable.

Projects are designed to test your mastery of course material as well as your programming skills; think of them as “take-home exams” and don’t communicate with anyone about possible solutions. This project focuses on digital circuits, both combinational circuits and circuits with memory.

Problem 1: Negation Circuit (20%)

Design a circuit that negates an 8-bit integer in two’s-complement representation. The circuit has 8 inputs labeled i0, i1, i2, …, i7 on which bits 0, 1, 2, …, 7 of the original integer arrive. The circuit has 8 outputs labeled q0, q1, q2, …, q7 on which bits 0, 1, 2, …, 7 of the negated integer are produced.

Recall that the most-significant bit, bit 7 in this case, is the sign bit in two’s-complement. As discussed in lecture, in order to negate an integer in two’s-complement, we first invert (flip) all the bits, then add 1. Here are some examples:

i      i | q      q ||
7  ..  0 | 7  ..  0 || Explanation
00000000 | 00000000 || inverts to 11111111, adding 1 results in 00000000
00000001 | 11111111 || inverts to 11111110, adding 1 results in 11111111
11111110 | 00000010 || inverts to 00000001, adding 1 results in 00000010
10000000 | 10000000 || inverts to 01111111, adding 1 results in 10000000

In the first line we negate 0 which is 0 again. In the second line we negate 1, resulting in the two’s-complement representation for -1. In the third line we start from -2 and get a result of 2. Finally, in the fourth line we “negate” -128 which results in -128 again; recall that the “most negative integer” cannot be negated in two’s-complement.

You don’t have to design/document the full gate-level circuitry for this problem, a “block diagram” is enough. You should explain each block (what are the inputs and outputs, how does it work internally) and explain how these blocks are connected to yield the final 8-bit negation circuit. Make sure you don’t forget to explain how all the inputs and outputs of your “blocks” are wired up!

The real “challenge” here is to make a circuit that is as simple as possible internally. If you hand in the “obvious” solution you can get at most 15%. If you hand in a “simpler” solution, one that takes, say, about half as many gates to implement, you can get the full 20%. In all likelihood you will have to invent a new “block” for that “simpler” solution, and you will want to describe how it works in a lot of detail to convince us that you know what you are doing.


Problem 2: RS Latches using NOR Gates (20%)

In lecture we discussed RS latches built from NAND gates in some detail. Here you’ll repeat some of that process for latches built from NOR gates instead:

  1. For the basic NOR RS latch, carefully derive the circuit’s behavior depending on the values of R and S. Your main goal is to identify the values of R and S that will result in the HOLD, SET, RESET, and ILLEGAL inputs for the NOR RS latch, but you should also discuss the NOR RS latch more generally.
  2. Explain the additional circuitry necessary to turn the NOR RS latch into an edge-triggered D-type master-slave flip-flop. Make sure you discuss in what sense the resulting flip-flop differs from the one built out of NAND RS latches. Do they have the same number of gates? Do they have the same “propagation delay” as it were? Anything else you can think of?

After completing this problem, you have to “erase” the NOR stuff from your brain again because the remaining problems assume that you’re using latches and flip-flops based on NAND gates, just as we did in lecture.

Problem 3: Shift Register (40%)

Design a 4-bit shift register out of edge-triggered D-type master-slave flip-flops. The shift register has 4 inputs and 4 outputs for the data stored in the register (4 parallel lines to read/write the bit pattern in the register). The outputs should be available continously and should represent the current value stored in the register. The inputs should only be sampled (and transferred into the register) when an external load signal LD is high.

If the LD signal is low, then the shift register will perform either a left shift or a right shift on each clock pulse, depending on an external DIR signal. If DIR is low, the register shifts to the left (toward the most-significant bit), if DIR is high, the register shifts to the right (toward the least-significant bit). A bit that would “shift out” is “shifted back in” at the opposite end of the register. An example (assuming LD and DIR are both low!) may make this clearer (each arrow represents a clock pulse):

... --> 0001 --> 0010 --> 0100 --> 1000 --> 0001 --> ...

In this example the binary number represents the content of the shift register with the most-significant bit as the left-most digit. (Just like you should expect!)


Problem 4: Reliability of Memory (20%)

You are manufacturing random-access memory (RAM) modules for computer systems. You build these modules out of edge-triggered D-type master-slave flip-flops which in turn rely on D-type latches as we discussed in lecture. (Note that this is a rather fantastic fiction, but this is a homework problem after all, nothing more.)

Assume that you can manufacture D-type latches with 99.999999% reliablity: whenever you manufacture a D-type latch, the chance for it operating correctly “forever” is 99.999999%.

Ignoring all other possible problems, what is the chance that a 1 MB (= 1024 x 1024 bytes, also known as a mebibyte these days) memory module will operate correctly?

If we want to manufacture a 4 GB (= 4 x 1024 x 1024 x 1024 bytes, also known as 4 gibibytes these days) memory module that has a 99% chance of operating correctly, what kind of reliability do we have to expect of our D-type latch manufacturing processes?


General Hints


Please follow the submission instructions as detailed on Piazza. Make sure that your tarball contains no derived files whatsoever (i.e. no object files, no executable files, etc.), but allows building all required derived files. Make sure to include a Makefile that sets the appropriate compiler flags as detailed on Piazza and builds all programs by default.

Include a plain text README file (not README.txt or README.docx or whatnot) that briefly explains what your programs do and contains any other notes you want us to check out before grading. Your answers to written problems should be in your README file as well! Make sure you explain the notation you are using for boolean formulas (the C-type notation is recommended). Make sure to include explanatory notes and detailed derivations that tell us how you solved the problem in question (and convince us that you really did the work). If you include ASCII diagrams, they can go directly into the README file; if your diagrams are in PDF, there should be one PDF file for each problem, so problem1.pdf, problem2.pdf, and so on. Pay attention to the size of your PDF files, project submissions cannot be bigger than 2 MB!

Finally, make sure to include your name and email address in every file you turn in (well, in every file for which it makes sense to do so anyway)!


For reference, here is a short explanation of the grading criteria; some of the criteria don’t apply to all problems, and not all of the criteria are used on all projects.

Packaging refers to the proper organization of the stuff you hand in, following both the guidelines for Deliverables above as well as the general submission instructions for projects on Piazza.

Style refers to both programming and presentation style. Programming style includes things like consistent indentation, appropriate identifier names, useful comments, suitable documentation, etc. Style also includes proper modularization of your code (into functions, modules, etc.), proper use of static and extern, etc. Simple, clean, readable code is what you should be aiming for. For C (and, if allowed, C++) programs, make sure you follow the style guide posted on Piazza! Presentation style refers to your README file and (possibly!) your PDF files for diagrams. Your presentation should be clear, structured problem-by-problem, broken into sections (and paragraphs!) as appropriate. Lines should be at most 80 characters in length, broken by UNIX linefeeds. (You may use Markdown format if you so choose, but everything must still be perfectly readable without rendering Markdown to another format.) Diagrams should be clearly labeled, cleanly layed out, and generally a pleasure to look at.

Performance refers to how fast/with how little memory your programs or circuits can produce the required results compared to other submissions.

Functionality refers to your programs or circuits being able to do what they should according to the specification given above; if the specification is ambiguous, ask for clarification! (It also refers to you simply doing the required work, beyond programming or circuit design!)

If your programs cannot be built you will get no points whatsoever. If your programs cannot be built without warnings using the required compiler options given on Piazza we will take off 10% (except if you document a very good reason). If your programs cannot be built using make we will take off 10%. If valgrind detects memory errors in your programs, we will take off 10%. If your programs fail miserably even once, i.e. terminate with an exception of any kind or dump core, we will take off 10% (for each such case).