Old version
This is the CS 111 site as it appeared on May 10, 2018.
Problem Set 5 FAQ
If you don’t see your question here, post it on Piazza or come to office hours! See the links in the navigation bar for both of those options.
Problem 2
-
How do we start the Full Adder?
If you look at the lecture notes on arithmetic circuits, you will find the truth table and a partial model for that circuit. You will need to use minterm expansion twice: once to complete the portion of the circuit that deals with the
s
bit, and once to create the portion of the circuit that deals with thec_out
bit.
Problem 3
-
How do we start the 4-bit Ripple-Carry Adder?
In lecture, we constructed a 2-bit Ripple-Carry Adder using two Full Adders. For the 4-bit Ripple-Carry Adder, you should extend this approach with more full adders so that you can add 4-bit numbers.
Problem 4
-
How should I start the 4x1 Multiplier? Will I need to use my Full Adder?
You will not need your Full Adder for the 4x1 multipler. Instead, notice that you are essentially just multiplying a 4-bit number by either 1 or 0. If you were to write this out by hand, each bit in the output would either be the same as the input bit, or 0. This depends on the 1-bit value
y
that we are multiplying by. Which logic gate could give us this behavior?If you work through the multiplication one bit at a time, you should only need to use one gate for each output bit (with 4 gates total).
Problem 5
-
How do I combine my 4x1 Multiplier and 4-Bit Adder to create the 4x2 Multiplier?
If you look at the lecture notes on arithmetic circuits, you will see a high-level description of how to implement the 4x2 Multiplier. To start, you can use two 4x1 Multipliers to produce two partial products. You will then need to add up the results using your 4-Bit Ripple Carry Adder. This may appear awkward since you will need to add a 4-bit number to a 5-bit number, but the lecture notes show you how to arrange the addition so that you only add two 4-bit numbers to get the final output.
Problem 6
-
How do I set the error bit in the 3x2 Divider?
If both
x_0
andx_1
are 0, then theerror
output should be 1 since division by 0 is undefined. You should be able to do this using a single logic gate (in addition to the NOT gates that we’ve given you for each input). Remember that it doesn’t matter what you set the other output bits to in this case. -
I’m taking the minterm-expansion approach to this problem, and I need one of my OR gates to have more than 8 inputs, but the maximum that Logicly allows is 8. What can I do?
You can chain two
OR
gates together. Feed some of the inputs into oneOR
gate, and then feed the output of thatOR
gate into a secondOR
gate along with the rest of the original set of inputs.
Part II General questions
Note
If you are confused about how a particular Hmmm instruction works, you should check the HMMM Reference.
-
When do we use the
nop
instruction?The
nop
instruction does nothing in your program. It is the same thing as empty space in your python code. In assembly, it can be used as a place holder so that you do not have to renumber lines as you add lines to your program. As an example, let’s say we want to implement the factorial program we reviewed in lecture. We know that we are finished whenr1
is equal to zero, but we are not sure how to implement the rest of the program. Usingnop
, we can give ourselves some room to try things out without having to renumber lines.00 read r1 01 setn r2 1 02 jeqz r1 08 03 nop 04 nop 05 nop 06 nop 07 nop 08 write r2 09 halt
Now you can replace the
nop
instructions with your own code and not have to spend time renumbering the lines. This will also save you from needing to fix any jump instructions. In this example, thejeqz
instruction on line02
can continue to jump to line08
, even after we replace some of thenop
instructions. -
Why is my use of the
copy
instruction not working?Remember that the destination of copy comes first, then the source.
For example, suppose that you want to copy a value from register
r6
into registerr5
. You would do so as follows:# correct copy r5 r6 # r5 = r6
Make sure that you do not mistakenly do this:
# incorrect copy r6 r5 # r6 = r5
In addition, be sure to check that you are not copying from the wrong register.
-
I’m getting an assembly error for one of my programs, and I can’t figure out why. Do you have any suggestions?
Check to make sure that you don’t have any special characters (for example:
$
, quotes,&
) in your comments. Try to remove all such characters, and limit your comments to letters, numbers, spaces, and the#
symbol. -
How does the debugger work?
You should be able to complete this assignment without using the debugger. However, if you are interested, here are a few commands that will allow you to use it effectively:
-
First, enter debugging mode by entering
y
in response to the question that is asked when you run your program. -
Entering ‘step’ will execute only the next instruction, and then let you type in more commands.
-
Entering
p
will display the contents of all of the registers. -
Entering ‘c’ will run all of the remaining instructions.
When you start the debugger, your program is not being run. To start the first instruction, type
step
and the first instruction will be run. If it’s a read instruction, you’ll have to enter the input. You can then enterp
to see the value of registers, and then typestep
to run the next instruction. Continuing to usestep
andp
will allow you to see how the registers change as your code executes.When you are done, and you want to run the rest of the code, type
c
and the rest of the program will run. Note that all of the instructions will be printed, so the output will be pretty verbose.We also encourage you to watch our video on how to use Hmmm, which includes a look at how to use the debugger.
-
Problem 7
-
What do I need to output in Problem 7?
Your program will read a number
n
and compute the cube ofn
. You must displayn
cubed and then count downward all the way to0
.For example, if we run your program with an input of
2
, we should get the following output:8 7 6 5 4 3 2 1 0
Problem 8
-
How do I compute the power for Problem 8?
You should model your code for Problem 8 on the factorial program that we gave you.
In that program, we start by designating a register to store/accumulate the result of the factorial, and we initialize the value in that register. Then, in the loop formed by lines 02-05, we repeatedly multiply the current result by the value of the register that stores the current value of
n
. Oncen
reaches 0, we know that we can write the value of the result register.You should do something similar for this problem. That is, you should designate a register to store/accumulate the result of raising the base
b
to some powern
. What initial value could you give this register? How should you update this result inside your loop?
Problem 9
-
I’m having trouble getting started on this problem. Do you have any additional suggestions?
First, make sure that you are modeling your assembly code on the provided Python code. In the Python code, the
distance
function is called twice, and the only thing that the function does is compute the distance between its two inputs. In the same way, your assembly-language function should also be called twice: once to compute the distance between the reference valuex0
and the first candidate valuex1
, and once to compute the distance betweenx0
and the second candidate valuex2
. And the function should only compute the distance between its two inputs; it should not do anything else. All of the remaining tasks should go in the portion of the program that comes before the function.Another good model for this problem is the following assembly-language program from lecture:
00 read r1 01 read r2 02 read r3 03 call r14 09 04 copy r1 r13 05 copy r2 r3 06 call r14 09 07 write r13 08 halt 09 sub r4 r1 r2 10 jgtz r4 13 11 copy r13 r1 12 jumpr r14 13 copy r13 r2 14 jumpr r14
This program determines the smallest of three values input by the user. To do so, it uses a function that determines the smaller of two values. The function consists of lines
09
-14
. It obtains its two inputs inr1
andr2
, and it puts its return value (the smaller of its two inputs) inr13
.The function is called twice: once on line
03
to find the smaller of the first two user inputs (the ones originally read intor1
andr2
), and once on line06
to find the smaller value from the result of the first call and the third user input (the one read intor3
).It is also worth comparing the two calls to the function. In the first call, we want to find the smaller of the first two user inputs, and because those user inputs are already in the same registers used for the inputs to the function (
r1
andr2
), we don’t need to do any additional preparation for the function call. However, we do need to prepare for the second call, which is used to find the smaller value from the result of the first call and the third user input (the one stored inr3
). Because those values are not already in the registers used for the function’s inputs, we need to use twocopy
commands (the ones on lines04
and05
) to put those values inr1
andr2
before we make the second call to the function.