Lab 2: Two-Function Calculator
Part B: Multipliers and Calculator
Lab 2 will give you experience designing, implementing, testing, and prototyping more complicated combinational logic using the Verilog hardware description language. This lab will primarily leverage concepts from Topic 2: Combinational Logic, Topic 3: Boolean Algebra, and Topic 4: Combinational Building Blocks including experience with adders, multiplexors, and multipliers. This lab will also reinforce three key abstraction principles: modularity, hierarchy, and regularity.
You will be implementing a two-function calculator that takes as input two binary values and then calculates either the sum or the product of these two values. The input values and the result will be displayed on seven-segment displays using your Verilog hardware design from Lab 1. Your implementation will mostly use gate-level modeling, but you will also start to explore very simple register-transfer-level modeling. Parts of the calculator will be used in future labs. The lab includes four parts:
-
Part A: Adders and Muxes
- Due 9/25 @ 11:59pm via GitHub
- Students should work on Part A before, during, and after your assigned lab section during the week of 9/22
-
Part B: Multipliers and Calculator
- Due 10/2 @ 11:59pm via GitHub
- Plan to start on Part B during the week of 9/22
- Even though Part B is due on 10/2 you still need the code ready to go before your lab section the week of 9/29!
-
Part C: FPGA Prototype
- Due week of 9/29 during assigned lab section
- Even though completed with a partner, every student must turn in their own paper check-off sheet in their lab section!
-
Part D: Report
- Due week of 9/29, three days after lab section @ 11:59pm via Canvas
- Post-lab survey on Canvas is due at the same time as the report
All parts of Lab 2 must be done with a partner. You can confirm your partner on Canvas (Click on People, then Groups, then search for your name to find your lab group).
Both students must contribute to all parts!
It is not acceptable for one student to exclusively work on the code while the other student exclusively works on the report. It is not acceptable for one student to exclusively work on hardware design while the other student exclusively works on testing. Both students must contribute to all parts. Student understanding of Verilog design and testing will be assessed on the prelim exams, final exam, and Verilog coding exam. The instructors will also survey the Git commit log on GitHub to confirm that both students are contributing equally. If you are using pair programming, then both students must take turns using their own account so both students have representative Git commits. Students should create commits after finishing each step of the lab, so their contribution is clear in the Git commit log. A student's whose contribution is limited as represented by the Git commit log will receive a significant deduction to their lab score.
This handout assumes that you have read and understand the course tutorials and that you have attended the discussion sections. This handout assumed you have successfully completed Part A. You should have already cloned your individual remote repository, so use git pull to ensure you have any recent updates before working on your lab assignment.
where XX
should be replaced with your group number. Students must try
to get Part B working before their lab section the week of 9/29. If you
have to finish Part B at the beginning of your lab section the week of
9/29 then you will likely not be able to finish Part C.
Your repo includes the following files in the lab2
subdirectory for
Part B. These files are for modeling real hardware using the
synthesizable subset of Verilog.
Multiplier_1x16b_GL.v
: 1-bit by 16-bit multplierMultiplier_2x16b_GL.v
: 2-bit by 16-bit multplierMultiplier_2x16b_RTL.v
: 2-bit by 16-bit register-transfer-level multiplierCalculator_GL.v
: Two-function calculator supporting addition and multiplication
The lab2/test
subdirectory includes the following test libraries and
test benches for Part B.
Multiplier_1x16b_GL-test.v
: Tests for 1-bit by 16-bit multplierMultiplier_2x16b_GL-test.v
: Tests for 2-bit by 16-bit multplierMultiplier_2x16b_RTL-test.v
: Tests for 2-bit by 16-bit register-transfer-level multiplierCalculator_GL-test.v
: Tests for two-function calculator
Your repo includes the following file in the lab1/sim
subdirectory.
This file is for an interactive simulator for final testing of your
hardware in a similar context to what you will be doing in Part C on the
actual hardware in the lab.
caculator-sim.v
: Interactive simulator for two-function calculator
Part B is divided into four steps.
- Step 1. Implement and test
Multiplier_1x16b_GL
- Step 2. Implement and test
Multiplier_2x16b_GL
- Step 3. Implement and test
Multiplier_2x16b_RTL
- Step 4. Implement and test
Calculator_GL
Consider having one partner work on the hardware implementation while the other partner works on the test cases in parallel for one module; then switch roles for the next module.
1. Interface and Implementation Specification
In Part B, you will be using the components you implemented and tested in Part A to implement a simple multiplier and ultimately a two-function calculator that takes as input two binary values and then calculates either the sum or the product of these two values. This section describe the required interface (i.e., the ports for the module and the module's functional behavior) before describing the required implementation (i.e., what goes inside the module) for each combinational building block.
1.1. One-bit by 16-Bit Multiplier
A one-bit by 16-bit multiplier multiplies a 16-bit input value by a
one-bit input value to determine a 16-bit product output. Review the
lecture notes for more on multipliers and then implement this simple
multiplier in Multiplier_1x16b_GL
. Use explicit gate-level modeling.
1.2. Two-bit by 16-Bit Multiplier
A two-bit by 16-bit multiplier multiplies a 16-bit input value by a two-bit input value to determine an 16-bit product output.
We use two one-bit by 16-bit multipliers to create the two partial products, and then we use an 16-bit adder to sum these two partial products to get the final result. If the output overflows then the implementation should truncate by using the lower 16 bits of the product.
Review the lecture nodes for more on multipliers and then implement this
multiplier in Multiplier_2x16b_GL
by instantiating two
Multiplier_1x16b_GL
modules and one AdderCarrySelect_16b_GL
and
correctly connecting all of the ports. You will need to use the include
Verilog preprocessor macro to include the appropriate child modules. You
will likely need some internal wires. Note that you may also have some
unused signals (i.e., the carry output from the adder and the most
significant bit of the sum). These unused signals will cause verilator
linting errors. You can use the ECE2300_UNUSED
Verilog preprocessor
macro to avoid unused signal errors.
1.3. Two-bit by 16-Bit Register-Transfer-Level Multiplier
Similar to our 16-bit RTL adder, we can also implement a two-bit by
16-bit RTL multplier. Instead of implementing the multiplier by
instantiating various hardware modules, we can use RTL modeling through
the *
operator to implement a 16-bit multiplier in a single line of
Verilog. Implement such a two-bit by 16-bit RTL multiplier in
Multiplier_16b_RTL
.
1.4. Two-Function Calculator
We can now put our adder and multiplier together using a 16-bit
two-to-one mux to create a two-function calculator. The calculator has an
op
input to select which operation we want to perform. If op
is zero
then we perform addition; if op
is one then we perform multiplication.
Note that you will need to connect just the least-significant two bits of
input in1
to the multiplier's input in1
.
Implement the calculator in Calculator_GL.v
by instantiating an
AdderCarrySelect_16b_GL
module, an Multiplier_2x16b_GL
module, and a
Mux2_16b_GL
module and then correctly connecting all of the ports. You will
likely need some internal wires. You will need to use the include
Verilog
preprocessor macro to include the appropriate child modules. You may also need
to use an extra Verilog snippet to avoid unused signal errors.
2. Testing Strategy
You will use a similar strategy as in Part A to ensure all of your implementations are correct. You will need to use a combination of basic, directed, and random testing to make a compelling case for correctness for Part B. Be sure to carefully test for situations where the output of the multiplication needs to be truncated.
2.1. Simulator
We have provided you a simple calculator simulator which will emulate what you will prototype during Part C. After finishing your implementation for the complete two-function calculator, you can build and run the calculator simulator like this:
% cd ${HOME}/ece2300/groupXX/lab2-calc/build
% make calculator-sim
% ./calculator-sim +in0-switches=00100 +in1-switches=00011 +button=0
% ./calculator-sim +in0-switches=00100 +in1-switches=00011 +button=1
The switches are connected to the inputs of the calculator, and the
button is connected to the op
input of the calculator. The calculator
simulator will show what the six seven segment displays would look like
on the FPGA prototype.
3. Lab Code Submission
To submit your code you simply push your code to GitHub. You can push
your code as many times as you like before the deadline. Students are
responsible for going to the GitHub website for their repository, browsing
the source code, and confirming the code on GitHub is the code they want
to submit. Be sure to verify your code is passing your tests
both on ecelinux
and on GitHub Actions. Your design code will be
assessed both in terms of code quality, verification quality, and
functionality.
3.1. Part A Revisions
If your design is failing some tests from Part A, then you should fix whatever is wrong. If your design is passing your tests but failing our tests you should browse the staff tests to see how to improve your own testing. Fixing whatever is wrong now can improve your code functionality score and also ensures that you can use your work from this lab in future labs.
To revise your submission, simply push any updates to your tests and/or your hardware designs to GiHub just like normal. You do not need to switch branches; just push your changes to the main branch like normal. Make sure your updates are passing all of your (potentially updated) tests on the main branch on GitHub Actions. After pushing your updated code, you must enter a comment on the grading pull request page that explains what was wrong and how you fixed it. The instructors will then take care of merging your changes into the grading pull request. You should not rely on the instructor merging your revision into the pull request to see if your code passes the staff tests; you should copy whatever staff tests are important into your own test benches. The only way we can increase your score after a revision is if you clearly explain what was wrong and how you fixed it. If you fix your code on the main branch and do not explain it in the grading pull request then you will not receive a revised score!
All Part A revisions need to be finalized by the due date for Part B. No revisions are allowed for Part B code.
3.2. Code and Verification Quality
Code and verification quality will be assessed in the same way as for Part A.
3.3. Functionality
Your functionality score will be determined by running your code against a series of tests developed by the instructors to test its correctness. Note that we will be using the automated build system to test your final code submission as shown below.